@nori-zk/mina-token-bridge
Version:
A Mina zk-program contract allowing users to mint tokens on Nori Bridge.
332 lines • 13.2 kB
JavaScript
import { assign, fromObservable, fromPromise, setup } from 'xstate';
import { getCanComputeEthProof$, getCanMint$, getDepositProcessingStatus$, } from '../rx/deposit.js';
// Define actors
const depositProcessingStatusActor = fromObservable(({ input, }) => {
return getDepositProcessingStatus$(input.depositBlockNumber, input.ethStateTopic$, input.bridgeStateTopic$, input.bridgeTimingsTopic$);
});
const canComputeEthProofActor = fromObservable(({ input, }) => {
return getCanComputeEthProof$(getDepositProcessingStatus$(input.depositBlockNumber, input.ethStateTopic$, input.bridgeStateTopic$, input.bridgeTimingsTopic$));
});
const canMintActor = fromObservable(({ input, }) => {
return getCanMint$(getDepositProcessingStatus$(input.depositBlockNumber, input.ethStateTopic$, input.bridgeStateTopic$, input.bridgeTimingsTopic$));
});
// Define deposit machine with topics as initial context.
export const getDepositMachine = (initialContext) => setup({
types: {
context: {},
events: {},
},
guards: {
hasComputedEthProof: ({ context }) => context.computedEthProof !== null,
hasDepositMintTx: ({ context }) => context.depositMintTx !== null,
hasActiveDepositNumber: ({ context }) => context.activeDepositNumber !== null,
canComputeEthProof: ({ context }) => context.canComputeStatus === 'CanCompute',
canMint: ({ context }) => context.canMintStatus === 'ReadyToMint',
isMissedOpportunity: ({ context }) => context.canComputeStatus === 'MissedMintingOpportunity' ||
context.canMintStatus === 'MissedMintingOpportunity',
},
actors: {
depositProcessingStatusActor,
canComputeEthProofActor,
canMintActor,
computeEthProofService: fromPromise(({ input }) => {
return new Promise((resolve) => {
setTimeout(() => resolve(`eth-proof-${input.depositBlockNumber}`), 1000);
});
}),
buildMintTxService: fromPromise(({ input, }) => {
return new Promise((resolve) => {
setTimeout(() => resolve(`mint-tx-${input.depositBlockNumber}`), 1000);
});
}),
submitMintTxService: fromPromise(({ input }) => {
return new Promise((resolve) => {
setTimeout(() => {
console.log(`Submitted mint tx: ${input.mintTx}`);
resolve();
}, 1000);
});
}),
},
}).createMachine({
id: 'deposit',
initial: 'checking',
context: {
activeDepositNumber: (() => {
const numStr = window.localStorage.getItem('activeDepositNumber');
return numStr !== null ? Number(numStr) : null;
})(),
depositMintTx: window.localStorage.getItem('depositMintTx'),
computedEthProof: window.localStorage.getItem('computedEthProof'),
processingStatus: null,
canComputeStatus: null,
canMintStatus: null,
ethStateTopic$: initialContext.ethStateTopic$,
bridgeStateTopic$: initialContext.bridgeStateTopic$,
bridgeTimingsTopic$: initialContext.bridgeTimingsTopic$,
},
states: {
checking: {
entry: assign({
activeDepositNumber: () => {
const numStr = window.localStorage.getItem('activeDepositNumber');
return numStr !== null ? Number(numStr) : null;
},
depositMintTx: () => window.localStorage.getItem('depositMintTx'),
computedEthProof: () => window.localStorage.getItem('computedEthProof'),
}),
always: [
{
target: 'hasComputedEthProof',
guard: 'hasComputedEthProof',
},
{ target: 'hasDepositMintTx', guard: 'hasDepositMintTx' },
{
target: 'hasActiveDepositNumber',
guard: 'hasActiveDepositNumber',
},
{ target: 'noActiveDepositNumber' },
],
},
noActiveDepositNumber: {
on: {
SET_DEPOSIT_NUMBER: {
actions: assign({
activeDepositNumber: ({ event }) => {
window.localStorage.setItem('activeDepositNumber', event.value.toString());
return event.value;
},
}),
target: 'hasActiveDepositNumber',
},
},
},
hasActiveDepositNumber: {
entry: assign({
processingStatus: () => null,
canComputeStatus: () => null,
canMintStatus: () => null,
}),
invoke: [
{
id: 'depositProcessingStatus',
src: 'depositProcessingStatusActor',
input: ({ context }) => ({
depositBlockNumber: context.activeDepositNumber,
ethStateTopic$: context.ethStateTopic$,
bridgeStateTopic$: context.bridgeStateTopic$,
bridgeTimingsTopic$: context.bridgeTimingsTopic$,
}),
onSnapshot: {
actions: assign({
processingStatus: ({ event }) => {
/*console.log(
'onSnapshotdepositProcessingStatus',
event
);*/
return event.snapshot.context;
},
}),
},
},
{
id: 'canComputeEthProof',
src: 'canComputeEthProofActor',
input: ({ context }) => ({
depositBlockNumber: context.activeDepositNumber,
ethStateTopic$: context.ethStateTopic$,
bridgeStateTopic$: context.bridgeStateTopic$,
bridgeTimingsTopic$: context.bridgeTimingsTopic$,
}),
onSnapshot: {
actions: assign({
canComputeStatus: ({ event }) => {
/*console.log(
'onSnapshotcanComputeEthProof',
event
);*/
return event.snapshot.context;
},
}),
},
},
{
id: 'canMint',
src: 'canMintActor',
input: ({ context }) => ({
depositBlockNumber: context.activeDepositNumber,
ethStateTopic$: context.ethStateTopic$,
bridgeStateTopic$: context.bridgeStateTopic$,
bridgeTimingsTopic$: context.bridgeTimingsTopic$,
}),
onSnapshot: {
actions: assign({
canMintStatus: ({ event }) => {
/*console.log(
'onSnapshotcanMintActor',
event
);*/
return event.snapshot.context;
},
}),
},
},
],
always: [
{
target: 'checkingCanCompute',
guard: 'canComputeEthProof',
},
{
target: 'missedOpportunity',
guard: 'isMissedOpportunity',
},
],
},
checkingCanCompute: {
invoke: {
src: 'canComputeEthProofActor',
input: ({ context }) => ({
depositBlockNumber: context.activeDepositNumber,
ethStateTopic$: context.ethStateTopic$,
bridgeStateTopic$: context.bridgeStateTopic$,
bridgeTimingsTopic$: context.bridgeTimingsTopic$,
}),
onSnapshot: {
actions: assign({
canComputeStatus: ({ event }) => event.snapshot.context,
}),
},
},
always: [
{
target: 'computingEthProof',
guard: 'canComputeEthProof',
},
{
target: 'missedOpportunity',
guard: 'isMissedOpportunity',
},
],
},
canComputeEvaluation: {
always: [
{
target: 'computingEthProof',
guard: 'canComputeEthProof',
},
{
target: 'missedOpportunity',
guard: 'isMissedOpportunity',
},
{ target: 'hasActiveDepositNumber' },
],
},
computingEthProof: {
invoke: {
src: 'computeEthProofService',
input: ({ context }) => ({
depositBlockNumber: context.activeDepositNumber,
}),
onDone: {
actions: assign({
computedEthProof: ({ event }) => {
const proof = event.output;
window.localStorage.setItem('computedEthProof', proof);
return proof;
},
}),
target: 'checking',
},
},
},
hasComputedEthProof: {
entry: assign({
canMintStatus: () => null,
}),
invoke: {
src: 'canMintActor',
input: ({ context }) => ({
depositBlockNumber: context.activeDepositNumber,
ethStateTopic$: context.ethStateTopic$,
bridgeStateTopic$: context.bridgeStateTopic$,
bridgeTimingsTopic$: context.bridgeTimingsTopic$,
}),
onSnapshot: {
actions: assign({
canMintStatus: ({ event }) => event.snapshot.context,
}),
},
},
always: [
{ target: 'buildingMintTx', guard: 'canMint' },
{
target: 'missedOpportunity',
guard: 'isMissedOpportunity',
},
{ target: 'hasComputedEthProof' },
],
},
canMintEvaluation: {
always: [
{ target: 'buildingMintTx', guard: 'canMint' },
{
target: 'missedOpportunity',
guard: 'isMissedOpportunity',
},
{ target: 'hasComputedEthProof' },
],
},
buildingMintTx: {
invoke: {
src: 'buildMintTxService',
input: ({ context }) => ({
depositBlockNumber: context.activeDepositNumber,
ethProof: context.computedEthProof,
}),
onDone: {
actions: assign({
depositMintTx: ({ event }) => {
const tx = event.output;
window.localStorage.setItem('depositMintTx', tx);
return tx;
},
}),
target: 'checking',
},
},
},
hasDepositMintTx: {
on: {
SUBMIT_MINT_TX: {
target: 'submittingMintTx',
},
},
},
submittingMintTx: {
invoke: {
src: 'submitMintTxService',
input: ({ context }) => ({
mintTx: context.depositMintTx,
}),
onDone: {
target: 'completed',
actions: () => {
window.localStorage.removeItem('activeDepositNumber');
window.localStorage.removeItem('depositMintTx');
window.localStorage.removeItem('computedEthProof');
},
},
},
},
missedOpportunity: {
type: 'final',
entry: () => console.log('Missed minting opportunity'),
},
completed: {
type: 'final',
entry: () => console.log('Deposit completed successfully'),
},
},
});
//# sourceMappingURL=deposit.js.map