From 5a2be7cb25959ffad8f78cbc0f959e65fdd33620 Mon Sep 17 00:00:00 2001 From: wighawag Date: Tue, 22 Aug 2023 22:50:01 +0100 Subject: [PATCH] working permit --- web/src/lib/ui/flows/CommitFlow.ts | 106 +++++++++++++++++++++++------ 1 file changed, 84 insertions(+), 22 deletions(-) diff --git a/web/src/lib/ui/flows/CommitFlow.ts b/web/src/lib/ui/flows/CommitFlow.ts index 70fe951f..aa54dca6 100644 --- a/web/src/lib/ui/flows/CommitFlow.ts +++ b/web/src/lib/ui/flows/CommitFlow.ts @@ -2,9 +2,13 @@ import {get, writable, type Subscriber, type Unsubscriber, type Writable} from ' import {actionState, localMoveToContractMove} from '$lib/action/ActionState'; import {contracts} from '$lib/web3'; import {prepareCommitment, zeroBytes32} from 'stratagems-common'; +import {initialContractsInfos} from '$lib/config'; +import {hexToSignature, zeroAddress} from 'viem'; export type CommitFlowData = { - state?: 'idle' | 'requireConfirmation' | 'permit' | 'tx' | 'fuzd' | 'complete'; + state: 'idle' | 'requireConfirmation' | 'permit' | 'tx' | 'fuzd' | 'complete'; + // requirePermitSignature: boolean; + permitSignature?: `0x${string}`; }; export class CommitFlow { @@ -12,7 +16,10 @@ export class CommitFlow { $store: CommitFlowData; constructor() { - this.$store = {}; + this.$store = { + state: 'idle', + // requirePermitSignature: false, + }; this.store = writable(this.$store); } @@ -20,32 +27,59 @@ export class CommitFlow { return this.store.subscribe(run, invalidate); } - requireConfirmation() { + requireConfirmation(amount: bigint) { this.$store.state = 'requireConfirmation'; this.store.set(this.$store); } cancel() { - this.$store.state = undefined; + this.$store.state = 'idle'; + this.$store.permitSignature = undefined; this.store.set(this.$store); } async confirm() { await contracts.execute(async ({contracts, account, connection}) => { + const actions = get(actionState); + const numActions = actions.length; + const tokenNeeded = + BigInt(initialContractsInfos.contracts.Stratagems.linkedData.numTokensPerGems.slice(0, -1)) * + BigInt(numActions); + + const chainId = parseInt(initialContractsInfos.chainId); + const tokenInReserve = await contracts.Stratagems.read.getTokensInReserve([account.address]); + + // TODO extra token to put in reserver + const amountToAdd = tokenNeeded > tokenInReserve ? tokenNeeded - tokenInReserve : 0n; this.$store.state = 'permit'; this.store.set(this.$store); - try { - await connection.provider.request({ - method: 'eth_signTypedData_v4', - params: [ - account.address, - { + if ((initialContractsInfos.contracts.Stratagems.linkedData.tokens as unknown) !== zeroAddress) { + if (amountToAdd > 0) { + const nonce = Number(await contracts.TestTokens.read.nonces([account.address])); + + // const domain = await contracts.TestTokens.read.eip712Domain(); + try { + const permit = { domain: { - chainId: 31337, name: 'Tokens', + chainId, verifyingContract: contracts.TestTokens.address, }, types: { + EIP712Domain: [ + { + name: 'name', + type: 'string', + }, + { + name: 'chainId', + type: 'uint256', + }, + { + name: 'verifyingContract', + type: 'address', + }, + ], Permit: [ {name: 'owner', type: 'address'}, {name: 'spender', type: 'address'}, @@ -57,23 +91,51 @@ export class CommitFlow { primaryType: 'Permit', message: { owner: account.address, - spender: contracts.TestTokens.address, - value: 1, - nonce: 0, + spender: contracts.Stratagems.address, + value: amountToAdd.toString(), + nonce, deadline: 0, }, - }, - ], - }); - } catch (e: any) { - this.$store.state = 'requireConfirmation'; + }; + const signature = await connection.provider.request({ + method: 'eth_signTypedData_v4', + //JSON.stringify( + params: [account.address, permit], + // ), + }); + + // 0x9c44b7e38020788fc1fc0e7ecb444662b6050678ed8e4ea56c253a55d83cc5cf4b6f581bd537e15a2421fa0d055418610a5c1917661354907b0d3b2539559ff21c + // 0x9c44b7e38020788fc1fc0e7ecb444662b6050678ed8e4ea56c253a55d83cc5cf4b6f581bd537e15a2421fa0d055418610a5c1917661354907b0d3b2539559ff21c + console.log({signature}); + + const {v, r, s} = hexToSignature(signature); + + this.$store.state = 'tx'; + this.store.set(this.$store); + + const secret = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const {hash, moves} = prepareCommitment(actions.map(localMoveToContractMove), secret); + await contracts.Stratagems.write.makeCommitmentWithExtraReserve( + [hash, amountToAdd, {deadline: 0n, value: amountToAdd, v: Number(v), r, s}], + {account: account.address}, + ); + } catch (e: any) { + this.$store.state = 'requireConfirmation'; + this.store.set(this.$store); + } + } else { + const secret = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const {hash, moves} = prepareCommitment(actions.map(localMoveToContractMove), secret); + await contracts.Stratagems.write.makeCommitment([hash], {account: account.address}); + } + } else { + this.$store.state = 'tx'; this.store.set(this.$store); } - this.$store.state = 'tx'; - this.store.set(this.$store); }); + // contracts.execute(async ({contracts, account}) => { - // const actions = get(actionState); + // // // TODO use signing key + nonce to generate secret deterninisticaly // const secret = '0x0000000000000000000000000000000000000000000000000000000000000000'; // const {hash, moves} = prepareCommitment(actions.map(localMoveToContractMove), secret);