Skip to content

Commit a7a4219

Browse files
committed
feat: added method for using nano headears in a create token tx
1 parent 04f29b6 commit a7a4219

File tree

8 files changed

+648
-196
lines changed

8 files changed

+648
-196
lines changed
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
import { HathorWallet } from '@hathor/wallet-lib';
2+
import type { NanoContractAction } from '@hathor/wallet-lib/lib/nano_contracts/types';
3+
import { createNanoContractCreateTokenTx } from '../../src/rpcMethods/createNanoContractCreateTokenTx';
4+
import {
5+
TriggerTypes,
6+
RpcMethods,
7+
CreateNanoContractCreateTokenTxRpcRequest,
8+
TriggerResponseTypes,
9+
RpcResponseTypes,
10+
} from '../../src/types';
11+
import { PromptRejectedError, InvalidParamsError } from '../../src/errors';
12+
13+
describe('createNanoContractCreateTokenTx', () => {
14+
let rpcRequest: CreateNanoContractCreateTokenTxRpcRequest;
15+
let wallet: HathorWallet;
16+
let promptHandler = jest.fn();
17+
18+
const nanoActions: NanoContractAction[] = [
19+
{
20+
type: 'deposit',
21+
address: 'test-address',
22+
token: '00',
23+
amount: 100n,
24+
} as NanoContractAction,
25+
];
26+
27+
const createTokenOptions = {
28+
name: 'TestToken',
29+
symbol: 'TT',
30+
amount: '100',
31+
address: 'wallet1',
32+
changeAddress: 'wallet1',
33+
createMint: true,
34+
mintAuthorityAddress: 'wallet1',
35+
allowExternalMintAuthorityAddress: false,
36+
createMelt: true,
37+
meltAuthorityAddress: 'wallet1',
38+
allowExternalMeltAuthorityAddress: false,
39+
data: ['test'],
40+
};
41+
42+
type NanoData = {
43+
blueprintId?: string;
44+
ncId?: string;
45+
actions?: NanoContractAction[];
46+
args?: unknown[];
47+
};
48+
49+
beforeEach(() => {
50+
rpcRequest = {
51+
method: RpcMethods.CreateNanoContractCreateTokenTx,
52+
params: {
53+
method: 'initialize',
54+
address: 'wallet1',
55+
data: {
56+
blueprintId: 'blueprint123',
57+
ncId: 'nc123',
58+
actions: nanoActions,
59+
args: [],
60+
},
61+
createTokenOptions,
62+
options: {},
63+
push_tx: true,
64+
},
65+
};
66+
67+
wallet = {
68+
createAndSendNanoContractCreateTokenTransaction: jest.fn(),
69+
createNanoContractCreateTokenTransaction: jest.fn(),
70+
} as unknown as HathorWallet;
71+
72+
promptHandler = jest.fn();
73+
});
74+
75+
it('should send a nano contract create token transaction successfully (push_tx true)', async () => {
76+
const pinCode = '1234';
77+
const response = { tx_id: 'mock-tx-id' };
78+
const rpcResponse = {
79+
type: RpcResponseTypes.CreateNanoContractCreateTokenTxResponse,
80+
response,
81+
};
82+
83+
promptHandler
84+
.mockResolvedValueOnce({
85+
type: TriggerResponseTypes.CreateNanoContractCreateTokenTxConfirmationResponse,
86+
data: {
87+
accepted: true,
88+
nano: {
89+
blueprintId: (rpcRequest.params.data as NanoData).blueprintId,
90+
ncId: (rpcRequest.params.data as NanoData).ncId,
91+
actions: (rpcRequest.params.data as NanoData).actions,
92+
args: (rpcRequest.params.data as NanoData).args,
93+
method: rpcRequest.params.method,
94+
pushTx: true,
95+
caller: 'wallet1',
96+
},
97+
token: createTokenOptions,
98+
},
99+
})
100+
.mockResolvedValueOnce({
101+
type: TriggerResponseTypes.PinRequestResponse,
102+
data: {
103+
accepted: true,
104+
pinCode,
105+
},
106+
});
107+
108+
(wallet.createAndSendNanoContractCreateTokenTransaction as jest.Mock).mockResolvedValue(response);
109+
110+
const result = await createNanoContractCreateTokenTx(rpcRequest, wallet, {}, promptHandler);
111+
112+
expect(promptHandler).toHaveBeenCalledWith(
113+
expect.objectContaining({
114+
type: TriggerTypes.CreateNanoContractCreateTokenTxConfirmationPrompt,
115+
}),
116+
{}
117+
);
118+
expect(promptHandler).toHaveBeenCalledWith(
119+
expect.objectContaining({
120+
type: TriggerTypes.PinConfirmationPrompt,
121+
}),
122+
{}
123+
);
124+
expect(wallet.createAndSendNanoContractCreateTokenTransaction).toHaveBeenCalledWith(
125+
rpcRequest.params.method,
126+
rpcRequest.params.address,
127+
expect.objectContaining({
128+
blueprintId: 'blueprint123',
129+
ncId: 'nc123',
130+
actions: nanoActions,
131+
method: rpcRequest.params.method,
132+
args: [],
133+
pushTx: true,
134+
}),
135+
createTokenOptions,
136+
expect.objectContaining({ pinCode })
137+
);
138+
expect(result).toEqual(rpcResponse);
139+
});
140+
141+
it('should create but not send the transaction (push_tx false)', async () => {
142+
rpcRequest.params.push_tx = false;
143+
const pinCode = '1234';
144+
const response = { tx_id: 'mock-tx-id' };
145+
promptHandler
146+
.mockResolvedValueOnce({
147+
type: TriggerResponseTypes.CreateNanoContractCreateTokenTxConfirmationResponse,
148+
data: {
149+
accepted: true,
150+
nano: {
151+
blueprintId: (rpcRequest.params.data as NanoData).blueprintId,
152+
ncId: (rpcRequest.params.data as NanoData).ncId,
153+
actions: (rpcRequest.params.data as NanoData).actions,
154+
args: (rpcRequest.params.data as NanoData).args,
155+
method: rpcRequest.params.method,
156+
pushTx: false,
157+
caller: 'wallet1',
158+
},
159+
token: createTokenOptions,
160+
},
161+
})
162+
.mockResolvedValueOnce({
163+
type: TriggerResponseTypes.PinRequestResponse,
164+
data: {
165+
accepted: true,
166+
pinCode,
167+
},
168+
});
169+
(wallet.createNanoContractCreateTokenTransaction as jest.Mock).mockResolvedValue(response);
170+
const result = await createNanoContractCreateTokenTx(rpcRequest, wallet, {}, promptHandler);
171+
expect(wallet.createNanoContractCreateTokenTransaction).toHaveBeenCalledWith(
172+
rpcRequest.params.method,
173+
rpcRequest.params.address,
174+
expect.objectContaining({
175+
blueprintId: 'blueprint123',
176+
ncId: 'nc123',
177+
actions: nanoActions,
178+
method: rpcRequest.params.method,
179+
args: [],
180+
pushTx: false,
181+
}),
182+
createTokenOptions,
183+
expect.objectContaining({ pinCode })
184+
);
185+
expect(result).toHaveProperty('type', RpcResponseTypes.CreateNanoContractCreateTokenTxResponse);
186+
});
187+
188+
it('should throw PromptRejectedError if the user rejects the confirmation prompt', async () => {
189+
promptHandler.mockResolvedValueOnce({
190+
type: TriggerResponseTypes.CreateNanoContractCreateTokenTxConfirmationResponse,
191+
data: { accepted: false },
192+
});
193+
await expect(createNanoContractCreateTokenTx(rpcRequest, wallet, {}, promptHandler)).rejects.toThrow(PromptRejectedError);
194+
});
195+
196+
it('should throw PromptRejectedError if the user rejects the PIN prompt', async () => {
197+
promptHandler
198+
.mockResolvedValueOnce({
199+
type: TriggerResponseTypes.CreateNanoContractCreateTokenTxConfirmationResponse,
200+
data: {
201+
accepted: true,
202+
nano: {
203+
blueprintId: (rpcRequest.params.data as NanoData).blueprintId,
204+
ncId: (rpcRequest.params.data as NanoData).ncId,
205+
actions: (rpcRequest.params.data as NanoData).actions,
206+
args: (rpcRequest.params.data as NanoData).args,
207+
method: rpcRequest.params.method,
208+
pushTx: true,
209+
caller: 'wallet1',
210+
},
211+
token: createTokenOptions,
212+
},
213+
})
214+
.mockResolvedValueOnce({
215+
type: TriggerResponseTypes.PinRequestResponse,
216+
data: { accepted: false },
217+
});
218+
await expect(createNanoContractCreateTokenTx(rpcRequest, wallet, {}, promptHandler)).rejects.toThrow(PromptRejectedError);
219+
});
220+
221+
it('should throw InvalidParamsError for invalid parameters', async () => {
222+
const invalidRequest = {
223+
method: RpcMethods.CreateNanoContractCreateTokenTx,
224+
params: {
225+
method: '', // Invalid: empty method
226+
address: '', // Invalid: empty address
227+
data: {},
228+
createTokenOptions: {},
229+
options: {},
230+
push_tx: true,
231+
},
232+
} as unknown as CreateNanoContractCreateTokenTxRpcRequest;
233+
await expect(createNanoContractCreateTokenTx(invalidRequest, wallet, {}, promptHandler)).rejects.toThrow(InvalidParamsError);
234+
});
235+
});

packages/hathor-rpc-handler/src/rpcHandler/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
CreateTokenRpcRequest,
2222
SignOracleDataRpcRequest,
2323
SendTransactionRpcRequest,
24+
CreateNanoContractCreateTokenTxRpcRequest,
2425
} from '../types';
2526
import {
2627
getAddress,
@@ -32,6 +33,7 @@ import {
3233
signWithAddress,
3334
createToken,
3435
sendTransaction,
36+
createNanoContractCreateTokenTx,
3537
} from '../rpcMethods';
3638
import { InvalidRpcMethod } from '../errors';
3739

@@ -96,6 +98,12 @@ export const handleRpcRequest = async (
9698
requestMetadata,
9799
promptHandler,
98100
);
101+
case RpcMethods.CreateNanoContractCreateTokenTx: return createNanoContractCreateTokenTx(
102+
request as CreateNanoContractCreateTokenTxRpcRequest,
103+
wallet,
104+
requestMetadata,
105+
promptHandler,
106+
);
99107
default: throw new InvalidRpcMethod();
100108
}
101109
};

0 commit comments

Comments
 (0)