Use signTypedData in poll init (#10)

This commit is contained in:
Szymon Szlachtowicz 2021-08-12 16:37:21 +02:00 committed by GitHub
parent dd9079554e
commit f6203b783f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 345 additions and 130 deletions

View File

@ -30,6 +30,7 @@
"typescript": "^4.3.5"
},
"dependencies": {
"eth-sig-util": "^3.0.1",
"ethers": "^5.4.4",
"js-waku": "^0.10.0",
"protons": "^2.0.1"

View File

@ -52,12 +52,14 @@ class WakuVoting {
endTime?: number
) {
const pollInit = await PollInitMsg.create(signer, question, answers, pollType, minToken, endTime)
const payload = PollInit.encode(pollInit)
if (payload && pollInit) {
const wakuMessage = await WakuMessage.fromBytes(payload, this.pollInitTopic, {
timestamp: new Date(pollInit.timestamp),
})
await this.waku?.relay.send(wakuMessage)
if (pollInit) {
const payload = PollInit.encode(pollInit)
if (payload) {
const wakuMessage = await WakuMessage.fromBytes(payload, this.pollInitTopic, {
timestamp: new Date(pollInit.timestamp),
})
await this.waku?.relay.send(wakuMessage)
}
}
}

View File

@ -1,8 +1,58 @@
import { PollType } from '../types/PollType'
import { BigNumber, utils } from 'ethers'
import { BigNumber, utils, Wallet } from 'ethers'
import { JsonRpcSigner } from '@ethersproject/providers'
import { PollInit } from 'protons'
import { Wallet } from 'ethers'
type Message = {
owner: string
timestamp: number
question: string
answers: string[]
pollType: PollType
endTime: number
minToken: BigNumber | undefined
}
export function createSignMsgParams(message: Message) {
const msgParams: any = {
domain: {
name: 'Waku polling',
version: '1',
},
message: {
owner: message.owner,
timestamp: new Date(message.timestamp).toLocaleDateString(),
question: message.question,
answers: message.answers,
pollType: message.pollType === PollType.WEIGHTED ? 'Weighted' : 'Non weighted',
endTime: new Date(message.endTime).toLocaleDateString(),
},
primaryType: 'Mail',
types: {
EIP712Domain: [
{ name: 'name', type: 'string' },
{ name: 'version', type: 'string' },
],
Mail: [
{ name: 'owner', type: 'address' },
{ name: 'timestamp', type: 'string' },
{ name: 'question', type: 'string' },
{ name: 'answers', type: 'string[]' },
{ name: 'pollType', type: 'string' },
{ name: 'endTime', type: 'string' },
],
},
}
if (message.pollType === PollType.NON_WEIGHTED) {
if (message.minToken) {
msgParams.message = { ...msgParams.message, minToken: message.minToken.toString() }
msgParams.types.Mail.push({ name: 'minToken', type: 'uint256' })
}
}
return msgParams
}
export class PollInitMsg {
public owner: string
public timestamp: number
@ -37,14 +87,15 @@ export class PollInitMsg {
this.signature = signature
}
static async create(
static async _createWithSignFunction(
signFunction: (params: string[]) => Promise<string | undefined>,
signer: JsonRpcSigner | Wallet,
question: string,
answers: string[],
pollType: PollType,
minToken?: BigNumber,
endTime?: number
): Promise<PollInitMsg> {
): Promise<PollInitMsg | undefined> {
const owner = await signer.getAddress()
const timestamp = Date.now()
let newEndTime = timestamp + 10000000
@ -52,32 +103,48 @@ export class PollInitMsg {
newEndTime = endTime
}
const msg: (string | number | BigNumber | PollType)[] = [
if (pollType === PollType.NON_WEIGHTED && !minToken) {
minToken = BigNumber.from(1)
}
const params = createSignMsgParams({
owner,
timestamp,
question,
answers.join(),
answers,
pollType,
newEndTime,
]
const types = ['address', 'uint256', 'string', 'string', 'uint8', 'uint256']
if (pollType === PollType.NON_WEIGHTED) {
if (minToken) {
msg.push(minToken)
} else {
msg.push(BigNumber.from(1))
minToken = BigNumber.from(1)
}
types.push('uint256')
endTime: newEndTime,
minToken,
})
const signature = await signFunction([owner, JSON.stringify(params)])
if (!signature) {
return undefined
}
const packedData = utils.arrayify(utils.solidityPack(types, msg))
const signature = await signer.signMessage(packedData)
const id = utils.solidityKeccak256(['address', 'uint256'], [owner, timestamp])
return new PollInitMsg(id, owner, signature, timestamp, question, answers, pollType, newEndTime, minToken)
}
static fromProto(payload: PollInit) {
static async create(
signer: JsonRpcSigner | Wallet,
question: string,
answers: string[],
pollType: PollType,
minToken?: BigNumber,
endTime?: number
): Promise<PollInitMsg | undefined> {
const signFunction = async (params: string[]) => {
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) {
const owner = utils.getAddress(utils.hexlify(payload.owner))
const timestamp = payload.timestamp
const question = payload.question
@ -85,29 +152,21 @@ export class PollInitMsg {
const pollType = payload.pollType
const endTime = payload.endTime
const signature = utils.hexlify(payload.signature)
let minToken = payload.minToken ? BigNumber.from(payload.minToken) : undefined
const minToken = payload.minToken ? BigNumber.from(payload.minToken) : undefined
const msg: (string | number | BigNumber | PollType)[] = [
const params = createSignMsgParams({
owner,
timestamp,
question,
answers.join(),
pollType,
answers,
endTime,
]
const types = ['address', 'uint256', 'string', 'string', 'uint8', 'uint256']
if (pollType === PollType.NON_WEIGHTED) {
if (minToken) {
msg.push(minToken)
types.push('uint256')
} else {
return undefined
}
} else {
minToken = undefined
}
const packedData = utils.arrayify(utils.solidityPack(types, msg))
const verifiedAddress = utils.verifyMessage(packedData, signature)
minToken,
pollType,
})
const verifiedAddress = recoverFunction({
data: params,
sig: signature,
})
if (verifiedAddress != owner) {
return undefined
}

View File

@ -2,6 +2,7 @@ import protons, { PollInit } from 'protons'
import { PollType } from '../../types/PollType'
import { utils } from 'ethers'
import { PollInitMsg } from '../../models/PollInitMsg'
import { recoverTypedSignature_v4 } from 'eth-sig-util'
const proto = protons(`
message PollInit {
@ -46,7 +47,11 @@ export function encode(pollInit: PollInitMsg) {
}
}
export function decode(payload: Uint8Array, timestamp: Date | undefined) {
export function decode(
payload: Uint8Array,
timestamp: Date | undefined,
recoverFunction?: ({ data, sig }: { data: any; sig: string }) => string
) {
try {
const msg = proto.PollInit.decode(payload)
if (!timestamp || timestamp.getTime() != msg.timestamp) {
@ -61,7 +66,10 @@ export function decode(payload: Uint8Array, timestamp: Date | undefined) {
msg.endTime &&
msg.signature
) {
return PollInitMsg.fromProto(msg)
if (recoverFunction) {
return PollInitMsg.fromProto(msg, recoverFunction)
}
return PollInitMsg.fromProto(msg, (e) => utils.getAddress(recoverTypedSignature_v4(e)))
}
} catch {
return undefined

View File

@ -1,82 +1,117 @@
import { expect } from 'chai'
import { PollInitMsg } from '../../src/models/PollInitMsg'
import { createSignMsgParams, PollInitMsg } from '../../src/models/PollInitMsg'
import { MockProvider } from 'ethereum-waffle'
import { PollType } from '../../src/types/PollType'
import { BigNumber, utils } from 'ethers'
import { BigNumber } from 'ethers'
describe('PollInitMsg', () => {
const provider = new MockProvider()
const [alice] = provider.getWallets()
it('success', async () => {
const poll = await PollInitMsg.create(alice, 'test', ['one', 'two', 'three'], PollType.WEIGHTED)
const poll = await PollInitMsg._createWithSignFunction(
async (params) => params.join(),
alice,
'test',
['one', 'two', 'three'],
PollType.WEIGHTED
)
expect(poll).to.not.be.undefined
expect(poll.owner).to.eq(alice.address)
expect(poll.endTime).to.eq(poll.timestamp + 10000000)
expect(poll.answers).to.deep.eq(['one', 'two', 'three'])
expect(poll.minToken).to.be.undefined
expect(poll.pollType).to.eq(PollType.WEIGHTED)
expect(poll.question).to.eq('test')
if (poll) {
expect(poll.owner).to.eq(alice.address)
expect(poll.endTime).to.eq(poll.timestamp + 10000000)
expect(poll.answers).to.deep.eq(['one', 'two', 'three'])
expect(poll.minToken).to.be.undefined
expect(poll.pollType).to.eq(PollType.WEIGHTED)
expect(poll.question).to.eq('test')
const types = ['address', 'uint256', 'string', 'string', 'uint8', 'uint256']
const msg = [poll.owner, poll.timestamp, poll.question, poll.answers.join(), poll.pollType, poll.endTime]
const packedData = utils.arrayify(utils.solidityPack(types, msg))
const verifiedAddress = utils.verifyMessage(packedData, poll.signature)
expect(verifiedAddress).to.eq(alice.address)
expect(poll.signature).to.eq(
[
poll.owner,
JSON.stringify(
createSignMsgParams({
owner: poll.owner,
answers: poll.answers,
endTime: poll.endTime,
pollType: poll.pollType,
minToken: poll.minToken,
question: poll.question,
timestamp: poll.timestamp,
})
),
].join()
)
}
})
it('success NON_WEIGHTED', async () => {
const poll = await PollInitMsg.create(
const poll = await PollInitMsg._createWithSignFunction(
async (params) => params.join(),
alice,
'test',
['one', 'two', 'three'],
PollType.NON_WEIGHTED,
BigNumber.from(123)
)
expect(poll).to.not.be.undefined
expect(poll?.minToken?.toNumber()).to.eq(123)
const types = ['address', 'uint256', 'string', 'string', 'uint8', 'uint256', 'uint256']
const msg = [
poll.owner,
poll.timestamp,
poll.question,
poll.answers.join(),
poll.pollType,
poll.endTime,
poll.minToken,
]
const packedData = utils.arrayify(utils.solidityPack(types, msg))
const verifiedAddress = utils.verifyMessage(packedData, poll.signature)
expect(verifiedAddress).to.eq(alice.address)
if (poll) {
expect(poll.signature).to.eq(
[
poll.owner,
JSON.stringify(
createSignMsgParams({
owner: poll.owner,
answers: poll.answers,
endTime: poll.endTime,
pollType: poll.pollType,
minToken: poll.minToken,
question: poll.question,
timestamp: poll.timestamp,
})
),
].join()
)
}
})
it('NON_WEIGHTED no minToken', async () => {
const poll = await PollInitMsg.create(alice, 'test', ['one', 'two', 'three'], PollType.NON_WEIGHTED)
const poll = await PollInitMsg._createWithSignFunction(
async (params) => params.join(),
alice,
'test',
['one', 'two', 'three'],
PollType.NON_WEIGHTED
)
expect(poll?.minToken?.toNumber()).to.eq(1)
expect(poll).to.not.be.undefined
if (poll) {
const msg = createSignMsgParams({
owner: poll.owner,
answers: poll.answers,
endTime: poll.endTime,
pollType: poll.pollType,
minToken: poll.minToken,
question: poll.question,
timestamp: poll.timestamp,
})
const types = ['address', 'uint256', 'string', 'string', 'uint8', 'uint256', 'uint256']
const msg = [
poll.owner,
poll.timestamp,
poll.question,
poll.answers.join(),
poll.pollType,
poll.endTime,
poll.minToken,
]
const packedData = utils.arrayify(utils.solidityPack(types, msg))
const verifiedAddress = utils.verifyMessage(packedData, poll.signature)
expect(verifiedAddress).to.eq(alice.address)
expect(poll.signature).to.eq([poll.owner, JSON.stringify(msg)].join())
}
})
it('specific end time', async () => {
const poll = await PollInitMsg.create(alice, 'test', ['one', 'two', 'three'], PollType.NON_WEIGHTED, undefined, 100)
const poll = await PollInitMsg._createWithSignFunction(
async () => 'a',
alice,
'test',
['one', 'two', 'three'],
PollType.NON_WEIGHTED,
undefined,
100
)
expect(poll?.endTime).to.eq(100)
})

View File

@ -9,13 +9,20 @@ describe('PollInit', () => {
const provider = new MockProvider()
const [alice] = provider.getWallets()
it('success', async () => {
const data = await PollInitMsg.create(alice, 'whats up', ['ab', 'cd', 'ef'], PollType.WEIGHTED)
const payload = PollInit.encode(data)
expect(payload).to.not.be.undefined
if (payload) {
expect(PollInit.decode(payload, new Date(data.timestamp))).to.deep.eq(data)
const data = await PollInitMsg._createWithSignFunction(
async () => '0x01',
alice,
'whats up',
['ab', 'cd', 'ef'],
PollType.WEIGHTED
)
expect(data).to.not.be.undefined
if (data) {
const payload = PollInit.encode(data)
expect(payload).to.not.be.undefined
if (payload) {
expect(PollInit.decode(payload, new Date(data.timestamp), () => data.owner)).to.deep.eq(data)
}
}
})
@ -28,29 +35,43 @@ describe('PollInit', () => {
})
it('NON_WEIGHTED init', async () => {
const data = await PollInitMsg.create(
const data = await PollInitMsg._createWithSignFunction(
async () => '0x01',
alice,
'whats up',
['ab', 'cd', 'ef'],
PollType.NON_WEIGHTED,
BigNumber.from(10)
)
const payload = PollInit.encode(data)
expect(payload).to.not.be.undefined
if (payload) {
expect(PollInit.decode(payload, new Date(data.timestamp))).to.deep.eq(data)
expect(data).to.not.be.undefined
if (data) {
const payload = PollInit.encode(data)
expect(payload).to.not.be.undefined
if (payload) {
expect(PollInit.decode(payload, new Date(data.timestamp), () => data.owner)).to.deep.eq(data)
}
}
})
it('NON_WEIGHTED no min token', async () => {
const data = await PollInitMsg.create(alice, 'whats up', ['ab', 'cd', 'ef'], PollType.NON_WEIGHTED)
const data = await PollInitMsg._createWithSignFunction(
async () => '0x01',
alice,
'whats up',
['ab', 'cd', 'ef'],
PollType.NON_WEIGHTED
)
expect(data).to.not.be.undefined
if (data) {
const payload = PollInit.encode(data)
const payload = PollInit.encode(data)
expect(payload).to.not.be.undefined
if (payload) {
expect(PollInit.decode(payload, new Date(data.timestamp))).to.deep.eq({ ...data, minToken: BigNumber.from(1) })
expect(payload).to.not.be.undefined
if (payload) {
expect(PollInit.decode(payload, new Date(data.timestamp), () => data.owner)).to.deep.eq({
...data,
minToken: BigNumber.from(1),
})
}
}
})
})

View File

@ -14,6 +14,7 @@
},
"dependencies": {
"@status-waku-voting/react-components": "link:../react-components",
"assert": "^2.0.0",
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.0",
"prettier": "^2.3.2",

View File

@ -22,7 +22,8 @@ module.exports = (env) => {
fallback: {
"buffer": require.resolve("buffer/"),
"crypto": require.resolve("crypto-browserify"),
"stream": require.resolve("stream-browserify")
"stream": require.resolve("stream-browserify"),
"assert": require.resolve("assert")
}
},
module: {

View File

@ -5,9 +5,7 @@ import { PollList } from './PollList'
import styled from 'styled-components'
import { PollType } from '@status-waku-voting/core/dist/esm/src/types/PollType'
const ethereum = (window as any).ethereum
const provider = new providers.Web3Provider(ethereum)
const provider = new providers.Web3Provider((window as any).ethereum)
type ExampleProps = {
appName: string
@ -24,14 +22,13 @@ function Example({ appName }: ExampleProps) {
const [selectedType, setSelectedType] = useState(PollType.WEIGHTED)
useEffect(() => {
ethereum.ethereum.on('accountsChanged', async () => {
provider.on('accountsChanged', async () => {
provider.send('eth_requestAccounts', [])
setSigner(provider.getSigner())
})
WakuVoting.create(appName, '0x01').then((e) => setWakuVoting(e))
provider.send('eth_requestAccounts', [])
}, [])
return (
<Wrapper>
{showNewPollBox && (

112
yarn.lock
View File

@ -895,8 +895,8 @@
"@status-waku-voting/core@link:packages/core":
version "1.0.0"
dependencies:
eth-sig-util "^3.0.1"
ethers "^5.4.4"
js-waku "^0.10.0"
protons "^2.0.1"
"@status-waku-voting/react-components@link:packages/react-components":
@ -1103,9 +1103,9 @@
integrity sha512-zxrTNFl9Z8boMJXs6ieqZP0wAhvkdzmHSxTlJabM16cf5G9xBc1uPRH5Bbv2omEDDiM8MzTfqTJXBf0Ba4xFWA==
"@types/node@>=13.7.0":
version "16.4.13"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.4.13.tgz#7dfd9c14661edc65cccd43a29eb454174642370d"
integrity sha512-bLL69sKtd25w7p1nvg9pigE4gtKVpGTPojBFLMkGHXuUgap2sLqQt2qUnqmVCDfzGUL0DRNZP+1prIZJbMeAXg==
version "16.6.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.0.tgz#0d5685f85066f94e97f19e8a67fe003c5fadacc4"
integrity sha512-OyiZPohMMjZEYqcVo/UJ04GyAxXOJEZO/FpzyXxcH4r/ArrVoXHf4MbUrkLp0Tz7/p1mMKpo5zJ6ZHl8XBNthQ==
"@types/node@^12.12.6":
version "12.20.19"
@ -1825,6 +1825,16 @@ assert-plus@1.0.0, assert-plus@^1.0.0:
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
assert@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/assert/-/assert-2.0.0.tgz#95fc1c616d48713510680f2eaf2d10dd22e02d32"
integrity sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==
dependencies:
es6-object-assign "^1.1.0"
is-nan "^1.2.1"
object-is "^1.0.1"
util "^0.12.0"
assertion-error@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
@ -1896,6 +1906,11 @@ atob@^2.1.2:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
available-typed-arrays@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.4.tgz#9e0ae84ecff20caae6a94a1c3bc39b955649b7a9"
integrity sha512-SA5mXJWrId1TaQjfxUYghbqQ/hYioKmLJvPJyDuYRtXXenFNMjj4hSSt1Cf1xsuXSXrtxrVC5Ot4eU6cOtBDdA==
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
@ -3991,7 +4006,7 @@ error-ex@^1.2.0, error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2:
es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2, es-abstract@^1.18.5:
version "1.18.5"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.5.tgz#9b10de7d4c206a3581fd5b2124233e04db49ae19"
integrity sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==
@ -4046,6 +4061,11 @@ es6-iterator@~2.0.3:
es5-ext "^0.10.35"
es6-symbol "^3.1.1"
es6-object-assign@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c"
integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=
es6-promisify@^6.1.1:
version "6.1.1"
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.1.1.tgz#46837651b7b06bf6fff893d03f29393668d01621"
@ -4341,6 +4361,16 @@ eth-sig-util@^1.4.2:
ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git"
ethereumjs-util "^5.1.1"
eth-sig-util@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/eth-sig-util/-/eth-sig-util-3.0.1.tgz#8753297c83a3f58346bd13547b59c4b2cd110c96"
integrity sha512-0Us50HiGGvZgjtWTyAI/+qTzYPMLy5Q451D0Xy68bxq1QMWdoOddDwGvsqcFT27uohKgalM9z/yxplyt+mY2iQ==
dependencies:
ethereumjs-abi "^0.6.8"
ethereumjs-util "^5.1.1"
tweetnacl "^1.0.3"
tweetnacl-util "^0.15.0"
eth-tx-summary@^3.1.2:
version "3.2.4"
resolved "https://registry.yarnpkg.com/eth-tx-summary/-/eth-tx-summary-3.2.4.tgz#e10eb95eb57cdfe549bf29f97f1e4f1db679035c"
@ -4424,7 +4454,7 @@ ethereumjs-abi@0.6.5:
bn.js "^4.10.0"
ethereumjs-util "^4.3.0"
ethereumjs-abi@0.6.8:
ethereumjs-abi@0.6.8, ethereumjs-abi@^0.6.8:
version "0.6.8"
resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz#71bc152db099f70e62f108b7cdfca1b362c6fcae"
integrity sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==
@ -5051,6 +5081,11 @@ for-in@^1.0.2:
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
foreach@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k=
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
@ -6166,6 +6201,13 @@ is-function@^1.0.1:
resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08"
integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==
is-generator-function@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72"
integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
dependencies:
has-tostringtag "^1.0.0"
is-glob@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
@ -6197,6 +6239,14 @@ is-loopback-addr@^1.0.0:
resolved "https://registry.yarnpkg.com/is-loopback-addr/-/is-loopback-addr-1.0.1.tgz#d4adf50d12d53100da62a397c61d6c83fe40aab9"
integrity sha512-DhWU/kqY7X2F6KrrVTu7mHlbd2Pbo4D1YkAzasBMjQs6lJAoefxaA6m6CpSX0K6pjt9D0b9PNFI5zduy/vzOYw==
is-nan@^1.2.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d"
integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==
dependencies:
call-bind "^1.0.0"
define-properties "^1.1.3"
is-negative-zero@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24"
@ -6308,6 +6358,17 @@ is-symbol@^1.0.2, is-symbol@^1.0.3:
dependencies:
has-symbols "^1.0.2"
is-typed-array@^1.1.3, is-typed-array@^1.1.6:
version "1.1.7"
resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.7.tgz#881ddc660b13cb8423b2090fa88c0fe37a83eb2f"
integrity sha512-VxlpTBGknhQ3o7YiVjIhdLU6+oD8dPz/79vvvH4F+S/c8608UCVa9fgDpa1kZgFoUST2DCgacc70UszKgzKuvA==
dependencies:
available-typed-arrays "^1.0.4"
call-bind "^1.0.2"
es-abstract "^1.18.5"
foreach "^2.0.5"
has-tostringtag "^1.0.0"
is-typedarray@^1.0.0, is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
@ -7851,9 +7912,9 @@ multibase@^0.7.0:
buffer "^5.5.0"
multibase@^4.0.1, multibase@^4.0.2:
version "4.0.4"
resolved "https://registry.yarnpkg.com/multibase/-/multibase-4.0.4.tgz#55ef53e6acce223c5a09341a8a3a3d973871a577"
integrity sha512-8/JmrdSGzlw6KTgAJCOqUBSGd1V6186i/X8dDCGy/lbCKrQ+1QB6f3HE+wPr7Tpdj4U3gutaj9jG2rNX6UpiJg==
version "4.0.5"
resolved "https://registry.yarnpkg.com/multibase/-/multibase-4.0.5.tgz#620293b524e01f504b750cef585c2bdc6ee1c64c"
integrity sha512-oqFkOYXdUkakxT8MqGyn5sE1KYeVt1zataOTvg688skQp6TVBv9XnouCcVO86XKFzh/UTiCGmEImTx6ZnPZ0qQ==
dependencies:
"@multiformats/base-x" "^4.0.1"
@ -7955,11 +8016,16 @@ nano-json-stream-parser@^0.1.2:
resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f"
integrity sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18=
nanoid@3.1.23, nanoid@^3.0.2, nanoid@^3.1.20:
nanoid@3.1.23:
version "3.1.23"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81"
integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==
nanoid@^3.0.2, nanoid@^3.1.20:
version "3.1.24"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.24.tgz#d7ac20215f595c26d314ee5671169a27b609025f"
integrity sha512-WNhqqgD4qH7TQdU9ujXfFa/hQI5rOGGnZq+JRmz4JwMZFCgSZVquTq3ORUSv6IC+Y41ACBYV8a8J1kPkqGIiQg==
nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
@ -10794,7 +10860,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
tweetnacl@^1.0.0:
tweetnacl@^1.0.0, tweetnacl@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
@ -11066,6 +11132,18 @@ util.promisify@^1.0.0:
has-symbols "^1.0.1"
object.getownpropertydescriptors "^2.1.1"
util@^0.12.0:
version "0.12.4"
resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253"
integrity sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==
dependencies:
inherits "^2.0.3"
is-arguments "^1.0.4"
is-generator-function "^1.0.7"
is-typed-array "^1.1.3"
safe-buffer "^5.1.2"
which-typed-array "^1.1.2"
utila@~0.4:
version "0.4.0"
resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
@ -11662,6 +11740,18 @@ which-module@^2.0.0:
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
which-typed-array@^1.1.2:
version "1.1.6"
resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.6.tgz#f3713d801da0720a7f26f50c596980a9f5c8b383"
integrity sha512-DdY984dGD5sQ7Tf+x1CkXzdg85b9uEel6nr4UkFg1LoE9OXv3uRuZhe5CoWdawhGACeFpEZXH8fFLQnDhbpm/Q==
dependencies:
available-typed-arrays "^1.0.4"
call-bind "^1.0.2"
es-abstract "^1.18.5"
foreach "^2.0.5"
has-tostringtag "^1.0.0"
is-typed-array "^1.1.6"
which@2.0.2, which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"