diff --git a/frontend/apps/battleship/src/features/game/assets/meta/battleship.meta.txt b/frontend/apps/battleship/src/features/game/assets/meta/battleship.meta.txt index 201be6cc1..bde061426 100644 --- a/frontend/apps/battleship/src/features/game/assets/meta/battleship.meta.txt +++ b/frontend/apps/battleship/src/features/game/assets/meta/battleship.meta.txt @@ -1 +1 @@ -0002000100000000000106000000010e00000000000000011000000001110000006d2578000834626174746c65736869705f696f38426174746c6573686970496e6974000008012c626f745f6164647265737304011c4163746f724964000118636f6e666967100118436f6e66696700000410106773746418636f6d6d6f6e287072696d6974697665731c4163746f724964000004000801205b75383b2033325d000008000003200000000c000c0000050300100834626174746c65736869705f696f18436f6e66696700001001346761735f666f725f737461727414010c7536340001306761735f666f725f6d6f766514010c7536340001546761735f746f5f64656c6574655f73657373696f6e14010c753634000144626c6f636b5f6475726174696f6e5f6d7314010c7536340000140000050600180834626174746c65736869705f696f40426174746c6573686970416374696f6e00012424537461727447616d6508011473686970731c0114536869707300014c73657373696f6e5f666f725f6163636f756e7424013c4f7074696f6e3c4163746f7249643e000000105475726e080110737465700c0108753800014c73657373696f6e5f666f725f6163636f756e7424013c4f7074696f6e3c4163746f7249643e000100244368616e6765426f7404010c626f7404011c4163746f72496400020028436c65617253746174650401486c656176655f6163746976655f67616d6573280110626f6f6c0003002844656c65746547616d65040138706c617965725f6164647265737304011c4163746f7249640004003443726561746553657373696f6e0c010c6b657904011c4163746f7249640001206475726174696f6e14010c75363400013c616c6c6f7765645f616374696f6e732c01585665633c416374696f6e73466f7253657373696f6e3e0005006044656c65746553657373696f6e46726f6d50726f6772616d04011c6163636f756e7404011c4163746f7249640006006044656c65746553657373696f6e46726f6d4163636f756e7400070030557064617465436f6e6669671001346761735f666f725f737461727434012c4f7074696f6e3c7536343e0001306761735f666f725f6d6f766534012c4f7074696f6e3c7536343e0001546761735f746f5f64656c6574655f73657373696f6e34012c4f7074696f6e3c7536343e000144626c6f636b5f6475726174696f6e5f6d7334012c4f7074696f6e3c7536343e000800001c0834626174746c65736869705f696f1453686970730000100118736869705f3120011c5665633c75383e000118736869705f3220011c5665633c75383e000118736869705f3320011c5665633c75383e000118736869705f3420011c5665633c75383e0000200000020c002404184f7074696f6e04045401040108104e6f6e6500000010536f6d6504000400000100002800000500002c0000023000300834626174746c65736869705f696f44416374696f6e73466f7253657373696f6e00010824537461727447616d65000000105475726e000100003404184f7074696f6e04045401140108104e6f6e6500000010536f6d650400140000010000380834626174746c65736869705f696f3c426174746c65736869705265706c79000118404d65737361676553656e74546f426f740000001c456e6447616d6504003c0158426174746c65736869705061727469636970616e747300010028426f744368616e676564040004011c4163746f7249640002003853657373696f6e437265617465640003003853657373696f6e44656c6574656400040034436f6e66696755706461746564000500003c0834626174746c65736869705f696f58426174746c65736869705061727469636970616e747300010818506c617965720000000c426f7400010000400834626174746c65736869705f696f28537461746551756572790001100c416c6c0000001047616d65040004011c4163746f72496400010034426f74436f6e747261637449640002005053657373696f6e466f725468654163636f756e74040004011c4163746f72496400030000440834626174746c65736869705f696f2853746174655265706c790001100c416c6c040048013c426174746c657368697053746174650000001047616d6504006c01444f7074696f6e3c47616d6553746174653e00010034426f74436f6e74726163744964040004011c4163746f7249640002005053657373696f6e466f725468654163636f756e74040070013c4f7074696f6e3c53657373696f6e3e00030000480834626174746c65736869705f696f3c426174746c6573686970537461746500000c011467616d65734c01645665633c284163746f7249642c2047616d655374617465293e00012c626f745f6164647265737304011c4163746f72496400011461646d696e04011c4163746f72496400004c00000250005000000408045400540834626174746c65736869705f696f2447616d6553746174650000280130706c617965725f626f61726458012c5665633c456e746974793e000124626f745f626f61726458012c5665633c456e746974793e000130706c617965725f73686970736001345665633c2875382c207538293e000124626f745f73686970736001345665633c2875382c207538293e0001107475726e6801784f7074696f6e3c426174746c65736869705061727469636970616e74733e00012873746172745f74696d6514010c753634000120656e645f74696d6514010c75363400012c746f74616c5f73686f747314010c75363400012467616d655f6f766572280110626f6f6c00012c67616d655f726573756c746801784f7074696f6e3c426174746c65736869705061727469636970616e74733e0000580000025c005c0834626174746c65736869705f696f18456e7469747900011c14456d7074790000001c556e6b6e6f776e000100204f63637570696564000200105368697000030010426f6f6d00040020426f6f6d536869700005002044656164536869700006000060000002640064000004080c0c006804184f7074696f6e040454013c0108104e6f6e6500000010536f6d6504003c00000100006c04184f7074696f6e04045401540108104e6f6e6500000010536f6d6504005400000100007004184f7074696f6e04045401740108104e6f6e6500000010536f6d650400740000010000740834626174746c65736869705f696f1c53657373696f6e00000c010c6b657904011c4163746f72496400011c6578706972657314010c75363400013c616c6c6f7765645f616374696f6e732c01585665633c416374696f6e73466f7253657373696f6e3e0000 +0002000100000000000106000000010f000000000001110000000001120000000113000000ad2884000834626174746c65736869705f696f38426174746c6573686970496e6974000008012c626f745f6164647265737304011c4163746f724964000118636f6e666967100118436f6e66696700000410106773746418636f6d6d6f6e287072696d6974697665731c4163746f724964000004000801205b75383b2033325d000008000003200000000c000c0000050300100834626174746c65736869705f696f18436f6e66696700001001346761735f666f725f737461727414010c7536340001306761735f666f725f6d6f766514010c7536340001546761735f746f5f64656c6574655f73657373696f6e14010c753634000144626c6f636b5f6475726174696f6e5f6d7314010c7536340000140000050600180834626174746c65736869705f696f40426174746c6573686970416374696f6e00012424537461727447616d6508011473686970731c0114536869707300014c73657373696f6e5f666f725f6163636f756e7424013c4f7074696f6e3c4163746f7249643e000000105475726e080110737465700c0108753800014c73657373696f6e5f666f725f6163636f756e7424013c4f7074696f6e3c4163746f7249643e000100244368616e6765426f7404010c626f7404011c4163746f72496400020028436c65617253746174650401486c656176655f6163746976655f67616d6573280110626f6f6c0003002844656c65746547616d65040138706c617965725f6164647265737304011c4163746f7249640004003443726561746553657373696f6e10010c6b657904011c4163746f7249640001206475726174696f6e14010c75363400013c616c6c6f7765645f616374696f6e732c01585665633c416374696f6e73466f7253657373696f6e3e0001247369676e617475726534013c4f7074696f6e3c5665633c75383e3e0005006044656c65746553657373696f6e46726f6d50726f6772616d04011c6163636f756e7404011c4163746f7249640006006044656c65746553657373696f6e46726f6d4163636f756e7400070030557064617465436f6e6669671001346761735f666f725f737461727438012c4f7074696f6e3c7536343e0001306761735f666f725f6d6f766538012c4f7074696f6e3c7536343e0001546761735f746f5f64656c6574655f73657373696f6e38012c4f7074696f6e3c7536343e000144626c6f636b5f6475726174696f6e5f6d7338012c4f7074696f6e3c7536343e000800001c0834626174746c65736869705f696f1453686970730000100118736869705f3120011c5665633c75383e000118736869705f3220011c5665633c75383e000118736869705f3320011c5665633c75383e000118736869705f3420011c5665633c75383e0000200000020c002404184f7074696f6e04045401040108104e6f6e6500000010536f6d6504000400000100002800000500002c0000023000300834626174746c65736869705f696f44416374696f6e73466f7253657373696f6e00010824537461727447616d65000000105475726e000100003404184f7074696f6e04045401200108104e6f6e6500000010536f6d6504002000000100003804184f7074696f6e04045401140108104e6f6e6500000010536f6d6504001400000100003c0834626174746c65736869705f696f3c426174746c65736869705265706c79000118404d65737361676553656e74546f426f740000001c456e6447616d650400400158426174746c65736869705061727469636970616e747300010028426f744368616e676564040004011c4163746f7249640002003853657373696f6e437265617465640003003853657373696f6e44656c6574656400040034436f6e6669675570646174656400050000400834626174746c65736869705f696f58426174746c65736869705061727469636970616e747300010818506c617965720000000c426f7400010000440834626174746c65736869705f696f345369676e61747572654461746100000c010c6b657904011c4163746f7249640001206475726174696f6e14010c75363400013c616c6c6f7765645f616374696f6e732c01585665633c416374696f6e73466f7253657373696f6e3e0000480834626174746c65736869705f696f28537461746551756572790001100c416c6c0000001047616d65040004011c4163746f72496400010034426f74436f6e747261637449640002005053657373696f6e466f725468654163636f756e74040004011c4163746f724964000300004c0834626174746c65736869705f696f2853746174655265706c790001100c416c6c040050013c426174746c657368697053746174650000001047616d6504007401444f7074696f6e3c47616d6553746174653e00010034426f74436f6e74726163744964040004011c4163746f7249640002005053657373696f6e466f725468654163636f756e74040078013c4f7074696f6e3c53657373696f6e3e00030000500834626174746c65736869705f696f3c426174746c6573686970537461746500000c011467616d65735401645665633c284163746f7249642c2047616d655374617465293e00012c626f745f6164647265737304011c4163746f72496400011461646d696e04011c4163746f72496400005400000258005800000408045c005c0834626174746c65736869705f696f2447616d6553746174650000280130706c617965725f626f61726460012c5665633c456e746974793e000124626f745f626f61726460012c5665633c456e746974793e000130706c617965725f73686970736801345665633c2875382c207538293e000124626f745f73686970736801345665633c2875382c207538293e0001107475726e7001784f7074696f6e3c426174746c65736869705061727469636970616e74733e00012873746172745f74696d6514010c753634000120656e645f74696d6514010c75363400012c746f74616c5f73686f747314010c75363400012467616d655f6f766572280110626f6f6c00012c67616d655f726573756c747001784f7074696f6e3c426174746c65736869705061727469636970616e74733e0000600000026400640834626174746c65736869705f696f18456e7469747900011c14456d7074790000001c556e6b6e6f776e000100204f63637570696564000200105368697000030010426f6f6d00040020426f6f6d5368697000050020446561645368697000060000680000026c006c000004080c0c007004184f7074696f6e04045401400108104e6f6e6500000010536f6d6504004000000100007404184f7074696f6e040454015c0108104e6f6e6500000010536f6d6504005c00000100007804184f7074696f6e040454017c0108104e6f6e6500000010536f6d6504007c00000100007c0834626174746c65736869705f696f1c53657373696f6e000010010c6b657904011c4163746f72496400011c6578706972657314010c75363400013c616c6c6f7765645f616374696f6e732c01585665633c416374696f6e73466f7253657373696f6e3e000140657870697265735f61745f626c6f636b80010c7533320000800000050500 \ No newline at end of file diff --git a/frontend/packages/ez-transactions/src/components/ez-transactions-switch/ez-transactions-switch.tsx b/frontend/packages/ez-transactions/src/components/ez-transactions-switch/ez-transactions-switch.tsx index 67874419f..75902a312 100644 --- a/frontend/packages/ez-transactions/src/components/ez-transactions-switch/ez-transactions-switch.tsx +++ b/frontend/packages/ez-transactions/src/components/ez-transactions-switch/ez-transactions-switch.tsx @@ -21,7 +21,7 @@ function EzTransactionsSwitch() { shouldIssueVoucher={!gasless.isEnabled} disabled={!signless.isSessionActive && gasless.isActive} message={!signless.isSessionActive && gasless.isActive ? 'Gasless Session is Active' : ''} - requiredBalance={gasless.isEnabled ? 11 : undefined} + requiredBalance={gasless.isEnabled ? 0 : undefined} /> ); diff --git a/frontend/packages/ez-transactions/src/context/consts.ts b/frontend/packages/ez-transactions/src/context/consts.ts index bbe31f98a..385662562 100644 --- a/frontend/packages/ez-transactions/src/context/consts.ts +++ b/frontend/packages/ez-transactions/src/context/consts.ts @@ -5,7 +5,7 @@ const DEFAULT_VALUES = { gasless: DEFAULT_GASLESS_CONTEXT, signless: { ...DEFAULT_SIGNLESS_CONTEXT, - onSessionCreate: async () => {}, + onSessionCreate: async (): Promise<`0x${string}`> => '0x', }, }; diff --git a/frontend/packages/ez-transactions/src/context/index.tsx b/frontend/packages/ez-transactions/src/context/index.tsx index 256e8cac0..d08d63f7b 100644 --- a/frontend/packages/ez-transactions/src/context/index.tsx +++ b/frontend/packages/ez-transactions/src/context/index.tsx @@ -22,7 +22,7 @@ function EzTransactionsProvider({ children }: Props) { const signlessContext = useSignlessTransactions(); - const onSessionCreate = (signlessAccountAddress: string) => gasless.requestVoucher(signlessAccountAddress); + const onSessionCreate = async (signlessAccountAddress: string) => gasless.requestVoucher(signlessAccountAddress); const signless = { ...signlessContext, diff --git a/frontend/packages/ez-transactions/src/context/types.ts b/frontend/packages/ez-transactions/src/context/types.ts index 06235a1eb..9297c6666 100644 --- a/frontend/packages/ez-transactions/src/context/types.ts +++ b/frontend/packages/ez-transactions/src/context/types.ts @@ -4,7 +4,7 @@ import { SignlessContext } from '@dapps-frontend/signless-transactions'; type Value = { gasless: GaslessContext; signless: SignlessContext & { - onSessionCreate: (signlessAccountAddress: string) => Promise; + onSessionCreate: (signlessAccountAddress: string) => Promise<`0x${string}`>; }; }; diff --git a/frontend/packages/gasless-transactions/src/context/consts.ts b/frontend/packages/gasless-transactions/src/context/consts.ts index 89958f94d..1317993cf 100644 --- a/frontend/packages/gasless-transactions/src/context/consts.ts +++ b/frontend/packages/gasless-transactions/src/context/consts.ts @@ -4,6 +4,6 @@ export const DEFAULT_GASLESS_CONTEXT = { isLoading: false, isEnabled: false, isActive: false, - requestVoucher: async () => {}, + requestVoucher: async (): Promise<`0x${string}`> => '0x', setIsEnabled: () => {}, }; diff --git a/frontend/packages/gasless-transactions/src/context/index.tsx b/frontend/packages/gasless-transactions/src/context/index.tsx index 229578619..bfd84734c 100644 --- a/frontend/packages/gasless-transactions/src/context/index.tsx +++ b/frontend/packages/gasless-transactions/src/context/index.tsx @@ -22,7 +22,7 @@ function GaslessTransactionsProvider({ backendAddress, programId, voucherLimit, const alert = useAlert(); const [accountAddress, setAccountAddress] = useState(); - const [voucherId, setVoucherId] = useState(); + const [voucherId, setVoucherId] = useState(); const { balance } = useBalance(voucherId); const [isLoading, , withLoading] = useLoading(); @@ -35,6 +35,8 @@ function GaslessTransactionsProvider({ backendAddress, programId, voucherLimit, getVoucherId(backendAddress, _accountAddress, programId).then((result) => { setAccountAddress(_accountAddress); setVoucherId(result); + + return result; }), ); diff --git a/frontend/packages/gasless-transactions/src/context/types.ts b/frontend/packages/gasless-transactions/src/context/types.ts index 3e7523d07..ea88c0db7 100644 --- a/frontend/packages/gasless-transactions/src/context/types.ts +++ b/frontend/packages/gasless-transactions/src/context/types.ts @@ -6,6 +6,6 @@ export type GaslessContext = { isLoading: boolean; isEnabled: boolean; isActive: boolean; - requestVoucher: (accountAddress: string) => Promise; + requestVoucher: (accountAddress: string) => Promise<`0x${string}`>; setIsEnabled: (value: boolean) => void; }; diff --git a/frontend/packages/gasless-transactions/src/context/utils.ts b/frontend/packages/gasless-transactions/src/context/utils.ts index 0dadee3dd..df8817cea 100644 --- a/frontend/packages/gasless-transactions/src/context/utils.ts +++ b/frontend/packages/gasless-transactions/src/context/utils.ts @@ -12,7 +12,7 @@ async function guardedFetch(...args: Parameters) return result; } -async function getVoucherId(backend: string, account: string, program: HexString) { +async function getVoucherId(backend: string, account: string, program: HexString): Promise<`0x${string}`> { const url = `${backend}gasless/voucher/request`; const method = 'POST'; const headers = { 'Content-Type': 'application/json' }; diff --git a/frontend/packages/signless-transactions/src/components/create-session-modal/create-session-modal.tsx b/frontend/packages/signless-transactions/src/components/create-session-modal/create-session-modal.tsx index 57c700ca2..f49632ee3 100644 --- a/frontend/packages/signless-transactions/src/components/create-session-modal/create-session-modal.tsx +++ b/frontend/packages/signless-transactions/src/components/create-session-modal/create-session-modal.tsx @@ -1,6 +1,5 @@ import { Button, Input, Modal, ModalProps, Select } from '@gear-js/vara-ui'; import { useApi, useBalanceFormat, useAccount } from '@gear-js/react-hooks'; -import { decodeAddress } from '@gear-js/api'; import { KeyringPair } from '@polkadot/keyring/types'; import { useMemo, useState } from 'react'; import { useForm } from 'react-hook-form'; @@ -18,13 +17,14 @@ import { DURATIONS, REQUIRED_MESSAGE, } from '../../consts'; +import { decodeAddress } from '@gear-js/api'; type Props = Pick & { - onSessionCreate?: (signlessAccountAddress: string) => Promise; + onSessionCreate?: (signlessAccountAddress: string) => Promise<`0x${string}`>; shouldIssueVoucher?: boolean; // no need to pass boolean, we can just conditionally pass onSessionCreate? }; -function CreateSessionModal({ close, onSessionCreate = async () => {}, shouldIssueVoucher = true }: Props) { +function CreateSessionModal({ close, onSessionCreate = async () => '0x', shouldIssueVoucher = true }: Props) { const { api } = useApi(); const { account } = useAccount(); const { getChainBalanceValue, getFormattedBalance } = useBalanceFormat(); @@ -62,9 +62,11 @@ function CreateSessionModal({ close, onSessionCreate = async () => {}, shouldIss const onSubmit = async ({ password, durationMinutes }: typeof DEFAULT_VALUES) => { if (!pair) throw new Error('Signless pair is not initialized'); + if (!account) throw new Error('Account not found'); const duration = getMilliseconds(Number(durationMinutes)); - const key = decodeAddress(pair.address); + + const key = shouldIssueVoucher ? decodeAddress(pair.address) : account!.decodedAddress; const allowedActions = ACTIONS; const onFinally = () => setIsLoading(false); @@ -86,9 +88,25 @@ function CreateSessionModal({ close, onSessionCreate = async () => {}, shouldIss close(); }; - if (!shouldIssueVoucher) await onSessionCreate(pairToSave.address); + if (!shouldIssueVoucher) { + const voucherId = await onSessionCreate(pairToSave.address); + + createSession({ duration, key, allowedActions }, issueVoucherValue, { + shouldIssueVoucher, + voucherId, + onSuccess, + onFinally, + pair: pairToSave, + }); + + return; + } - createSession({ duration, key, allowedActions }, issueVoucherValue, { shouldIssueVoucher, onSuccess, onFinally }); + createSession({ duration, key, allowedActions }, issueVoucherValue, { + shouldIssueVoucher, + onSuccess, + onFinally, + }); }; return ( diff --git a/frontend/packages/signless-transactions/src/components/enable-signless-session/enable-signless-session.tsx b/frontend/packages/signless-transactions/src/components/enable-signless-session/enable-signless-session.tsx index 9cf303001..ff2bbaa57 100644 --- a/frontend/packages/signless-transactions/src/components/enable-signless-session/enable-signless-session.tsx +++ b/frontend/packages/signless-transactions/src/components/enable-signless-session/enable-signless-session.tsx @@ -14,7 +14,7 @@ type Props = { shouldIssueVoucher?: boolean; message?: string; disabled?: boolean; - onSessionCreate?: (signlessAccountAddress: string) => Promise; + onSessionCreate?: (signlessAccountAddress: string) => Promise<`0x${string}`>; requiredBalance: number | undefined; }; @@ -49,7 +49,10 @@ function EnableSignlessSession(props: Props) { if (!pair) throw new Error('Signless pair not found'); setIsLoading(true); - deleteSession(session.key, pair, { onSuccess: onDeleteSessionSuccess, onFinally: onDeleteSessionFinally }); + deleteSession(session.key, pair, { + onSuccess: onDeleteSessionSuccess, + onFinally: onDeleteSessionFinally, + }); }; const handleSwitcherChange = (e: React.ChangeEvent) => { diff --git a/frontend/packages/signless-transactions/src/components/signless-transactions/signless-transactions.tsx b/frontend/packages/signless-transactions/src/components/signless-transactions/signless-transactions.tsx index d54612ffc..56eb759a8 100644 --- a/frontend/packages/signless-transactions/src/components/signless-transactions/signless-transactions.tsx +++ b/frontend/packages/signless-transactions/src/components/signless-transactions/signless-transactions.tsx @@ -16,7 +16,7 @@ import { AccountPair } from '../account-pair'; import { EnableSignlessSession } from '../enable-signless-session'; type Props = { - onSessionCreate?: (signlessAccountAddress: string) => Promise; + onSessionCreate?: (signlessAccountAddress: string) => Promise<`0x${string}`>; shouldIssueVoucher?: boolean; disabled?: boolean; requiredBalance?: number; diff --git a/frontend/packages/signless-transactions/src/context/hooks.ts b/frontend/packages/signless-transactions/src/context/hooks.ts index 4dcda48b5..5973b83a8 100644 --- a/frontend/packages/signless-transactions/src/context/hooks.ts +++ b/frontend/packages/signless-transactions/src/context/hooks.ts @@ -20,12 +20,12 @@ function useLatestVoucher(programId: HexString, address: string | undefined) { const decodedAddress = address ? decodeAddress(address) : ''; const { vouchers } = useVouchers(decodedAddress, programId); + const typedEntries = getTypedEntries(vouchers || {}); + const latestVoucher = useMemo(() => { - if (!vouchers) return undefined; + if (!vouchers || !typedEntries?.length) return undefined; - const [[id, voucher]] = getTypedEntries(vouchers).sort( - ([, voucher], [, nextVoucher]) => nextVoucher.expiry - voucher.expiry, - ); + const [[id, voucher]] = typedEntries.sort(([, voucher], [, nextVoucher]) => nextVoucher.expiry - voucher.expiry); return { ...voucher, id }; }, [vouchers]); diff --git a/frontend/packages/signless-transactions/src/hooks/use-create-session.ts b/frontend/packages/signless-transactions/src/hooks/use-create-session.ts index 5246114a5..7d99b41f2 100644 --- a/frontend/packages/signless-transactions/src/hooks/use-create-session.ts +++ b/frontend/packages/signless-transactions/src/hooks/use-create-session.ts @@ -1,7 +1,8 @@ -import { HexString, IVoucherDetails, ProgramMetadata } from '@gear-js/api'; -import { useAccount, useAlert, useApi } from '@gear-js/react-hooks'; +import { HexString, IVoucherDetails, ProgramMetadata, decodeAddress } from '@gear-js/api'; +import { Account, useAccount, useAlert, useApi } from '@gear-js/react-hooks'; import { AnyJson } from '@polkadot/types/types'; import { useBatchSignAndSend } from './use-batch-sign-and-send'; +import { web3FromSource } from '@polkadot/extension-dapp'; import { KeyringPair } from '@polkadot/keyring/types'; import { sendTransaction } from '../utils'; @@ -11,17 +12,11 @@ type Session = { allowedActions: string[]; }; -type Options = { - onSuccess: () => void; - onFinally: () => void; -}; - function useCreateSession(programId: HexString, metadata: ProgramMetadata | undefined) { const { api, isApiReady } = useApi(); const alert = useAlert(); const { account } = useAccount(); const { batchSignAndSend } = useBatchSignAndSend('all'); - const onError = (message: string) => alert.error(message); const isVoucherExpired = async ({ expiry }: IVoucherDetails) => { @@ -76,16 +71,60 @@ function useCreateSession(programId: HexString, metadata: ProgramMetadata | unde return api.voucher.update(session.key, voucher.id, { prolongDuration, balanceTopUp }); }; + type Options = { + onSuccess: () => void; + onFinally: () => void; + }; + + type CreeateSessionOptions = { + pair?: KeyringPair; + voucherId?: `0x${string}`; + shouldIssueVoucher: boolean; + }; + + const getAccountSignature = async (metadata: ProgramMetadata, account: Account, payloadToSign: Session) => { + const { signer } = await web3FromSource(account.meta.source); + const { signRaw } = signer; + + if (!signRaw) { + throw new Error('signRaw is not a function'); + } + + if (!metadata.types?.others?.output) { + throw new Error(`Metadata type doesn't exist`); + } + + const hexToSign = metadata.createType(metadata.types.others.output, payloadToSign).toHex(); + + return signRaw({ address: account.address, data: hexToSign, type: 'bytes' }); + }; const createSession = async ( session: Session, voucherValue: number, - { shouldIssueVoucher, ...options }: Options & { shouldIssueVoucher: boolean }, + { shouldIssueVoucher, voucherId, pair, ...options }: Options & CreeateSessionOptions, ) => { if (!isApiReady) throw new Error('API is not initialized'); if (!account) throw new Error('Account not found'); if (!metadata) throw new Error('Metadata not found'); + if (voucherId && pair) { + const { signature } = await getAccountSignature(metadata, account, { + ...session, + key: decodeAddress(pair.address), + }); + + const messageExtrinsic = getMessageExtrinsic({ + CreateSession: { ...session, signature }, + }); + + const voucherExtrinsic = api.voucher.call(voucherId, { SendMessage: messageExtrinsic }); + + await sendTransaction(voucherExtrinsic, pair, ['UserMessageSent'], { ...options, onError }); + + return; + } + const messageExtrinsic = getMessageExtrinsic({ CreateSession: session }); const txs = shouldIssueVoucher @@ -100,7 +139,10 @@ function useCreateSession(programId: HexString, metadata: ProgramMetadata | unde if (!account) throw new Error('Account not found'); if (!metadata) throw new Error('Metadata not found'); - const messageExtrinsic = getMessageExtrinsic({ DeleteSessionFromAccount: null }); + const messageExtrinsic = getMessageExtrinsic({ + DeleteSessionFromAccount: null, + }); + const txs = [messageExtrinsic]; const voucher = await getLatestVoucher(key); @@ -112,7 +154,7 @@ function useCreateSession(programId: HexString, metadata: ProgramMetadata | unde if (!isExpired) { const declineExtrinsic = api.voucher.call(voucher.id, { DeclineVoucher: null }); - await sendTransaction(declineExtrinsic, pair, ['VoucherDeclined']); + await sendTransaction(declineExtrinsic, pair, ['VoucherDeclined'], { ...options, onError }); } if (isOwner) { diff --git a/frontend/packages/signless-transactions/src/utils.ts b/frontend/packages/signless-transactions/src/utils.ts index b3240af54..2da2b0b64 100644 --- a/frontend/packages/signless-transactions/src/utils.ts +++ b/frontend/packages/signless-transactions/src/utils.ts @@ -4,6 +4,13 @@ import { SubmittableExtrinsic } from '@polkadot/api/types'; import { encodeAddress } from '@polkadot/keyring'; import { KeyringPair$Json, KeyringPair } from '@polkadot/keyring/types'; +type Options = Partial<{ + onSuccess: () => void; + onError: (error: string) => void; + onFinally: () => void; + pair?: KeyringPair; +}>; + const MULTIPLIER = { MS: 1000, SECONDS: 60, @@ -15,6 +22,7 @@ export async function sendTransaction, account: KeyringPair, methods: E[], + { onSuccess = () => {}, onError = () => {}, onFinally = () => {} }: Options = {}, ): Promise { const result: any = new Array(methods.length); return new Promise((resolve, reject) => { @@ -25,15 +33,20 @@ export async function sendTransaction { console.log(err); + onError(err); + onFinally(); reject(err.message); }); });