Skip to content

Commit c95709e

Browse files
committed
Ⓜ️ Add Mina SDK
1 parent e9dd657 commit c95709e

File tree

8 files changed

+189
-6
lines changed

8 files changed

+189
-6
lines changed

.github/workflows/test.yml

+26-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
branches: ["main"]
88

99
jobs:
10-
check:
10+
check_server_sdk:
1111
strategy:
1212
fail-fast: true
1313

@@ -16,20 +16,41 @@ jobs:
1616
- uses: actions/checkout@v3
1717
with:
1818
submodules: true
19-
2019
- uses: oven-sh/setup-bun@v1
21-
2220
- name: Build server-js
2321
run: |
2422
bun i
2523
make server-js
26-
2724
- name: Test server-js
2825
run: |
29-
bun i
3026
make server-js/test
3127
28+
check_client_sdk:
29+
strategy:
30+
fail-fast: true
31+
runs-on: ubuntu-latest
32+
steps:
33+
- uses: actions/checkout@v3
34+
with:
35+
submodules: true
36+
- uses: oven-sh/setup-bun@v1
3237
- name: Build client
3338
run: |
3439
bun i
3540
make client
41+
42+
check_mina_sdk:
43+
strategy:
44+
fail-fast: true
45+
runs-on: ubuntu-latest
46+
steps:
47+
- uses: actions/checkout@v3
48+
with:
49+
submodules: true
50+
- uses: actions/setup-node@v4
51+
with:
52+
node-version: "20.x"
53+
- name:
54+
run: |
55+
npm ci
56+
npm run test

mina/contracts/HumanIDs.test.ts

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import {
2+
AccountUpdate,
3+
MerkleTree,
4+
Mina,
5+
PrivateKey
6+
} from "o1js";
7+
import { HumanIDs } from "./HumanIDs";
8+
9+
describe('HumanIDs', () => {
10+
const deployerKey = PrivateKey.random();
11+
const deployer = deployerKey.toPublicKey();
12+
const senderKey = PrivateKey.random();
13+
const sender = senderKey.toPublicKey();
14+
const appKey = PrivateKey.random();
15+
const appAddr = appKey.toPublicKey();
16+
let app: HumanIDs;
17+
18+
beforeAll(() => HumanIDs.compile());
19+
20+
beforeEach(() => Mina.LocalBlockchain({ proofsEnabled: true })
21+
.then((local) => {
22+
Mina.setActiveInstance(local);
23+
app = new HumanIDs(appAddr);
24+
local.addAccount(deployer, "1000000000");
25+
}));
26+
27+
it('should deploy the app', async () => {
28+
const tree = new MerkleTree(128);
29+
30+
await Mina.transaction(deployer, async () => {
31+
AccountUpdate.fundNewAccount(deployer);
32+
return app.deploy()
33+
.then(() => app.initRoot(tree.getRoot()));
34+
}).then((txn) => txn.prove())
35+
.then((txn) => txn.sign([deployerKey, appKey]).send())
36+
.then((txn) => txn.wait());
37+
38+
console.log('Deployed HumanIDs contract at', app.address);
39+
});
40+
});

mina/contracts/HumanIDs.ts

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import {
2+
Field,
3+
MerkleWitness,
4+
SmartContract,
5+
State,
6+
method,
7+
state,
8+
} from "o1js";
9+
10+
class MerkleWitness128 extends MerkleWitness(128) { }
11+
12+
class HumanIDs extends SmartContract {
13+
@state(Field) treeRoot = State<Field>();
14+
15+
@method async initRoot(root: Field) {
16+
this.treeRoot.set(root);
17+
}
18+
19+
@method async addHumanID(
20+
humanID: Field,
21+
leafWitness: MerkleWitness128,
22+
) {
23+
const currentTreeRoot = this.treeRoot.getAndRequireEquals();
24+
25+
// TODO(oemerfurkan): Validate that the witness path matches a prefix of the
26+
// provided humanID
27+
28+
// humanId.sub(leafWitness.calculateIndex().mul(Field(2n ** 127n))).toBits(127);
29+
30+
currentTreeRoot.assertEquals(leafWitness.calculateRoot(Field(0)));
31+
this.treeRoot.set(leafWitness.calculateRoot(Field(1)));
32+
}
33+
}
34+
35+
export { HumanIDs, MerkleWitness128 };

mina/jest-resolver.cjs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module.exports = (request, options) => {
2+
return options.defaultResolver(request, {
3+
...options,
4+
packageFilter: (pkg) => {
5+
// When importing o1js, we specify the Node ESM import as Jest by default imports the web version
6+
if (pkg.name === 'o1js') {
7+
return {
8+
...pkg,
9+
main: pkg.exports.node.import,
10+
};
11+
}
12+
if (pkg.name === 'node-fetch') {
13+
return { ...pkg, main: pkg.main };
14+
}
15+
return {
16+
...pkg,
17+
main: pkg.module || pkg.main,
18+
};
19+
},
20+
});
21+
};

mina/jest.config.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/** @type {import('@ts-jest/dist/types').InitialOptionsTsJest} */
2+
export default {
3+
verbose: true,
4+
preset: 'ts-jest/presets/default-esm',
5+
testEnvironment: 'node',
6+
globals: {
7+
'ts-jest': {
8+
useESM: true,
9+
},
10+
},
11+
testTimeout: 1_000_000,
12+
transform: {
13+
'^.+\\.(t)s$': 'ts-jest',
14+
'^.+\\.(j)s$': 'babel-jest',
15+
},
16+
resolver: '<rootDir>/jest-resolver.cjs',
17+
transformIgnorePatterns: [
18+
'<rootDir>/node_modules/(?!(tslib|o1js/node_modules/tslib))',
19+
],
20+
modulePathIgnorePatterns: ['<rootDir>/build/'],
21+
moduleNameMapper: {
22+
'^(\\.{1,2}/.+)\\.js$': '$1',
23+
},
24+
};

mina/package.json

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"scripts": {
3+
"build": "tsc",
4+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
5+
},
6+
"dependencies": {
7+
"@types/jest": "^29.5.12",
8+
"o1js": "^1.1.0",
9+
"ts-jest": "^29.1.2",
10+
"typescript": "^5.4.5"
11+
},
12+
"type": "module"
13+
}

mina/tsconfig.json

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2020",
4+
"module": "es2022",
5+
"lib": [
6+
"dom",
7+
"esnext"
8+
],
9+
"outDir": "./build",
10+
"rootDir": ".",
11+
"strict": true,
12+
"strictPropertyInitialization": false, // to enable generic constructors, e.g. on CircuitValue
13+
"skipLibCheck": true,
14+
"forceConsistentCasingInFileNames": true,
15+
"esModuleInterop": true,
16+
"moduleResolution": "node",
17+
"experimentalDecorators": true,
18+
"emitDecoratorMetadata": true,
19+
"allowJs": true,
20+
"declaration": true,
21+
"sourceMap": true,
22+
"noFallthroughCasesInSwitch": true,
23+
"allowSyntheticDefaultImports": true,
24+
"useDefineForClassFields": false,
25+
},
26+
"include": [
27+
"./contracts"
28+
],
29+
}

0 commit comments

Comments
 (0)