Refactor initMsg typed signing (#11)
This commit is contained in:
parent
f6203b783f
commit
ac0279fda3
|
@ -3,6 +3,16 @@ import { BigNumber, utils, Wallet } from 'ethers'
|
||||||
import { JsonRpcSigner } from '@ethersproject/providers'
|
import { JsonRpcSigner } from '@ethersproject/providers'
|
||||||
import { PollInit } from 'protons'
|
import { PollInit } from 'protons'
|
||||||
|
|
||||||
|
function signFunction(signer: JsonRpcSigner | Wallet) {
|
||||||
|
return async (params: string[]) => {
|
||||||
|
if ('send' in signer.provider) {
|
||||||
|
return signer.provider.send('eth_signTypedData_v4', params)
|
||||||
|
} else {
|
||||||
|
throw `No send function in provider`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Message = {
|
type Message = {
|
||||||
owner: string
|
owner: string
|
||||||
timestamp: number
|
timestamp: number
|
||||||
|
@ -10,7 +20,7 @@ type Message = {
|
||||||
answers: string[]
|
answers: string[]
|
||||||
pollType: PollType
|
pollType: PollType
|
||||||
endTime: number
|
endTime: number
|
||||||
minToken: BigNumber | undefined
|
minToken?: BigNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createSignMsgParams(message: Message) {
|
export function createSignMsgParams(message: Message) {
|
||||||
|
@ -20,10 +30,8 @@ export function createSignMsgParams(message: Message) {
|
||||||
version: '1',
|
version: '1',
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
owner: message.owner,
|
...message,
|
||||||
timestamp: new Date(message.timestamp).toLocaleDateString(),
|
timestamp: new Date(message.timestamp).toLocaleDateString(),
|
||||||
question: message.question,
|
|
||||||
answers: message.answers,
|
|
||||||
pollType: message.pollType === PollType.WEIGHTED ? 'Weighted' : 'Non weighted',
|
pollType: message.pollType === PollType.WEIGHTED ? 'Weighted' : 'Non weighted',
|
||||||
endTime: new Date(message.endTime).toLocaleDateString(),
|
endTime: new Date(message.endTime).toLocaleDateString(),
|
||||||
},
|
},
|
||||||
|
@ -44,11 +52,9 @@ export function createSignMsgParams(message: Message) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.pollType === PollType.NON_WEIGHTED) {
|
if (message.pollType === PollType.NON_WEIGHTED && message.minToken) {
|
||||||
if (message.minToken) {
|
msgParams.message = { ...msgParams.message, minToken: message.minToken.toString() }
|
||||||
msgParams.message = { ...msgParams.message, minToken: message.minToken.toString() }
|
msgParams.types.Mail.push({ name: 'minToken', type: 'uint256' })
|
||||||
msgParams.types.Mail.push({ name: 'minToken', type: 'uint256' })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return msgParams
|
return msgParams
|
||||||
}
|
}
|
||||||
|
@ -64,27 +70,16 @@ export class PollInitMsg {
|
||||||
public signature: string
|
public signature: string
|
||||||
public id: string
|
public id: string
|
||||||
|
|
||||||
private constructor(
|
private constructor(signature: string, msg: Message) {
|
||||||
id: string,
|
this.id = utils.id([msg.owner, msg.timestamp, signature].join())
|
||||||
owner: string,
|
|
||||||
signature: string,
|
|
||||||
timestamp: number,
|
|
||||||
question: string,
|
|
||||||
answers: string[],
|
|
||||||
pollType: PollType,
|
|
||||||
endTime: number,
|
|
||||||
minToken?: BigNumber
|
|
||||||
) {
|
|
||||||
this.id = id
|
|
||||||
this.owner = owner
|
|
||||||
this.timestamp = timestamp
|
|
||||||
this.question = question
|
|
||||||
this.answers = answers
|
|
||||||
this.pollType = pollType
|
|
||||||
this.minToken = minToken
|
|
||||||
this.endTime = endTime
|
|
||||||
|
|
||||||
this.signature = signature
|
this.signature = signature
|
||||||
|
this.owner = msg.owner
|
||||||
|
this.timestamp = msg.timestamp
|
||||||
|
this.question = msg.question
|
||||||
|
this.answers = msg.answers
|
||||||
|
this.pollType = msg.pollType
|
||||||
|
this.minToken = msg.minToken
|
||||||
|
this.endTime = msg.endTime
|
||||||
}
|
}
|
||||||
|
|
||||||
static async _createWithSignFunction(
|
static async _createWithSignFunction(
|
||||||
|
@ -96,34 +91,31 @@ export class PollInitMsg {
|
||||||
minToken?: BigNumber,
|
minToken?: BigNumber,
|
||||||
endTime?: number
|
endTime?: number
|
||||||
): Promise<PollInitMsg | undefined> {
|
): Promise<PollInitMsg | undefined> {
|
||||||
const owner = await signer.getAddress()
|
|
||||||
const timestamp = Date.now()
|
const timestamp = Date.now()
|
||||||
let newEndTime = timestamp + 10000000
|
|
||||||
if (endTime) {
|
|
||||||
newEndTime = endTime
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pollType === PollType.NON_WEIGHTED && !minToken) {
|
if (pollType === PollType.NON_WEIGHTED && !minToken) {
|
||||||
minToken = BigNumber.from(1)
|
minToken = BigNumber.from(1)
|
||||||
}
|
}
|
||||||
|
const msg = {
|
||||||
const params = createSignMsgParams({
|
owner: await signer.getAddress(),
|
||||||
owner,
|
|
||||||
timestamp,
|
timestamp,
|
||||||
question,
|
question,
|
||||||
answers,
|
answers,
|
||||||
pollType,
|
pollType,
|
||||||
endTime: newEndTime,
|
endTime: endTime ? endTime : timestamp + 100000000,
|
||||||
minToken,
|
minToken,
|
||||||
})
|
|
||||||
|
|
||||||
const signature = await signFunction([owner, JSON.stringify(params)])
|
|
||||||
if (!signature) {
|
|
||||||
return undefined
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = utils.solidityKeccak256(['address', 'uint256'], [owner, timestamp])
|
const params = createSignMsgParams(msg)
|
||||||
return new PollInitMsg(id, owner, signature, timestamp, question, answers, pollType, newEndTime, minToken)
|
|
||||||
|
try {
|
||||||
|
const signature = await signFunction([msg.owner, JSON.stringify(params)])
|
||||||
|
if (!signature) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return new PollInitMsg(signature, msg)
|
||||||
|
} catch {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async create(
|
static async create(
|
||||||
|
@ -134,43 +126,27 @@ export class PollInitMsg {
|
||||||
minToken?: BigNumber,
|
minToken?: BigNumber,
|
||||||
endTime?: number
|
endTime?: number
|
||||||
): Promise<PollInitMsg | undefined> {
|
): Promise<PollInitMsg | undefined> {
|
||||||
const signFunction = async (params: string[]) => {
|
return this._createWithSignFunction(signFunction(signer), signer, question, answers, pollType, minToken, endTime)
|
||||||
if ('send' in signer.provider) {
|
|
||||||
return signer.provider.send('eth_signTypedData_v4', params)
|
|
||||||
} else {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this._createWithSignFunction(signFunction, signer, question, answers, pollType, minToken, endTime)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromProto(payload: PollInit, recoverFunction: ({ data, sig }: { data: any; sig: string }) => string) {
|
static fromProto(payload: PollInit, recoverFunction: ({ data, sig }: { data: any; sig: string }) => string) {
|
||||||
const owner = utils.getAddress(utils.hexlify(payload.owner))
|
|
||||||
const timestamp = payload.timestamp
|
|
||||||
const question = payload.question
|
|
||||||
const answers = payload.answers
|
|
||||||
const pollType = payload.pollType
|
|
||||||
const endTime = payload.endTime
|
|
||||||
const signature = utils.hexlify(payload.signature)
|
const signature = utils.hexlify(payload.signature)
|
||||||
const minToken = payload.minToken ? BigNumber.from(payload.minToken) : undefined
|
|
||||||
|
|
||||||
const params = createSignMsgParams({
|
const msg = {
|
||||||
owner,
|
...payload,
|
||||||
timestamp,
|
owner: utils.getAddress(utils.hexlify(payload.owner)),
|
||||||
question,
|
minToken: payload.minToken ? BigNumber.from(payload.minToken) : undefined,
|
||||||
answers,
|
}
|
||||||
endTime,
|
|
||||||
minToken,
|
const params = createSignMsgParams(msg)
|
||||||
pollType,
|
|
||||||
})
|
|
||||||
const verifiedAddress = recoverFunction({
|
const verifiedAddress = recoverFunction({
|
||||||
data: params,
|
data: params,
|
||||||
sig: signature,
|
sig: signature,
|
||||||
})
|
})
|
||||||
if (verifiedAddress != owner) {
|
if (verifiedAddress != msg.owner) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
const id = utils.solidityKeccak256(['address', 'uint256'], [owner, timestamp])
|
|
||||||
return new PollInitMsg(id, owner, signature, timestamp, question, answers, pollType, endTime, minToken)
|
return new PollInitMsg(signature, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ describe('PollInitMsg', () => {
|
||||||
expect(poll).to.not.be.undefined
|
expect(poll).to.not.be.undefined
|
||||||
if (poll) {
|
if (poll) {
|
||||||
expect(poll.owner).to.eq(alice.address)
|
expect(poll.owner).to.eq(alice.address)
|
||||||
expect(poll.endTime).to.eq(poll.timestamp + 10000000)
|
expect(poll.endTime).to.eq(poll.timestamp + 100000000)
|
||||||
expect(poll.answers).to.deep.eq(['one', 'two', 'three'])
|
expect(poll.answers).to.deep.eq(['one', 'two', 'three'])
|
||||||
expect(poll.minToken).to.be.undefined
|
expect(poll.minToken).to.be.undefined
|
||||||
expect(poll.pollType).to.eq(PollType.WEIGHTED)
|
expect(poll.pollType).to.eq(PollType.WEIGHTED)
|
||||||
|
@ -32,12 +32,12 @@ describe('PollInitMsg', () => {
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
createSignMsgParams({
|
createSignMsgParams({
|
||||||
owner: poll.owner,
|
owner: poll.owner,
|
||||||
answers: poll.answers,
|
|
||||||
endTime: poll.endTime,
|
|
||||||
pollType: poll.pollType,
|
|
||||||
minToken: poll.minToken,
|
|
||||||
question: poll.question,
|
|
||||||
timestamp: poll.timestamp,
|
timestamp: poll.timestamp,
|
||||||
|
question: poll.question,
|
||||||
|
answers: poll.answers,
|
||||||
|
pollType: poll.pollType,
|
||||||
|
endTime: poll.endTime,
|
||||||
|
minToken: poll.minToken,
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
].join()
|
].join()
|
||||||
|
@ -63,12 +63,12 @@ describe('PollInitMsg', () => {
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
createSignMsgParams({
|
createSignMsgParams({
|
||||||
owner: poll.owner,
|
owner: poll.owner,
|
||||||
answers: poll.answers,
|
|
||||||
endTime: poll.endTime,
|
|
||||||
pollType: poll.pollType,
|
|
||||||
minToken: poll.minToken,
|
|
||||||
question: poll.question,
|
|
||||||
timestamp: poll.timestamp,
|
timestamp: poll.timestamp,
|
||||||
|
question: poll.question,
|
||||||
|
answers: poll.answers,
|
||||||
|
pollType: poll.pollType,
|
||||||
|
endTime: poll.endTime,
|
||||||
|
minToken: poll.minToken,
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
].join()
|
].join()
|
||||||
|
@ -90,12 +90,12 @@ describe('PollInitMsg', () => {
|
||||||
if (poll) {
|
if (poll) {
|
||||||
const msg = createSignMsgParams({
|
const msg = createSignMsgParams({
|
||||||
owner: poll.owner,
|
owner: poll.owner,
|
||||||
answers: poll.answers,
|
|
||||||
endTime: poll.endTime,
|
|
||||||
pollType: poll.pollType,
|
|
||||||
minToken: poll.minToken,
|
|
||||||
question: poll.question,
|
|
||||||
timestamp: poll.timestamp,
|
timestamp: poll.timestamp,
|
||||||
|
question: poll.question,
|
||||||
|
answers: poll.answers,
|
||||||
|
pollType: poll.pollType,
|
||||||
|
endTime: poll.endTime,
|
||||||
|
minToken: poll.minToken,
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(poll.signature).to.eq([poll.owner, JSON.stringify(msg)].join())
|
expect(poll.signature).to.eq([poll.owner, JSON.stringify(msg)].join())
|
||||||
|
|
|
@ -16,9 +16,11 @@ export function Poll({ poll, wakuVoting, signer }: PollProps) {
|
||||||
const [selectedAnswer, setSelectedAnswer] = useState(0)
|
const [selectedAnswer, setSelectedAnswer] = useState(0)
|
||||||
const [tokenAmount, setTokenAmount] = useState(0)
|
const [tokenAmount, setTokenAmount] = useState(0)
|
||||||
const [address, setAddress] = useState('')
|
const [address, setAddress] = useState('')
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
signer.getAddress().then((e) => setAddress(e))
|
signer.getAddress().then((e) => setAddress(e))
|
||||||
}, [signer])
|
}, [signer])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PollWrapper>
|
<PollWrapper>
|
||||||
<PollTitle>
|
<PollTitle>
|
||||||
|
|
|
@ -22,7 +22,7 @@ function Example({ appName }: ExampleProps) {
|
||||||
const [selectedType, setSelectedType] = useState(PollType.WEIGHTED)
|
const [selectedType, setSelectedType] = useState(PollType.WEIGHTED)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
provider.on('accountsChanged', async () => {
|
;(window as any).ethereum.on('accountsChanged', async () => {
|
||||||
provider.send('eth_requestAccounts', [])
|
provider.send('eth_requestAccounts', [])
|
||||||
setSigner(provider.getSigner())
|
setSigner(provider.getSigner())
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue