Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: ProjectToken.RevenueSplitLeft mapping #324

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
# 4.0.0
# 4.0.2

## Bug Fixes:
- Fixed: unstake tokens atfer revenue share has been finalized.
- Fixed: transform raw json objects to `jsonb` properties while importing the offchain state.
- Fixed: `bigint` to `number` conversion in `getCumulativeHistoricalShareAllocation` custom resolver.
- Fixed duplicate notifications being received by users for featured NFTs.

# 4.0.1

## Misc

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "orion",
"version": "4.0.1",
"version": "4.0.2",
"engines": {
"node": ">=16"
},
Expand Down
24 changes: 9 additions & 15 deletions src/mappings/token/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
},
}: EventHandlerContext<'ProjectToken.TokenIssued'>) {
// create token
const totalSupply = initialAllocation.reduce((acc, [_, allocation]) => {

Check warning on line 80 in src/mappings/token/index.ts

View workflow job for this annotation

GitHub Actions / Local build, linting and formatting (ubuntu-latest, 16.x)

'_' is defined but never used
return acc + allocation.amount
}, BigInt(0))

Expand Down Expand Up @@ -384,7 +384,7 @@
buyerAccount.totalAmount += crtMinted
}

const activeAmm = await overlay.getRepository(AmmCurve).getByIdOrFail(token.currentAmmSaleId!)

Check warning on line 387 in src/mappings/token/index.ts

View workflow job for this annotation

GitHub Actions / Local build, linting and formatting (ubuntu-latest, 16.x)

Forbidden non-null assertion

activeAmm.mintedByAmm += crtMinted
const tx = overlay.getRepository(AmmTransaction).new({
Expand Down Expand Up @@ -443,7 +443,7 @@
.getOneByRelationOrFail('tokenId', tokenId.toString())
const channel = await overlay.getRepository(Channel).getByIdOrFail(tokenChannel.channelId)
token.totalSupply -= crtBurned
const activeAmm = await overlay.getRepository(AmmCurve).getByIdOrFail(token.currentAmmSaleId!)

Check warning on line 446 in src/mappings/token/index.ts

View workflow job for this annotation

GitHub Actions / Local build, linting and formatting (ubuntu-latest, 16.x)

Forbidden non-null assertion
const ammId = activeAmm.id

const sellerAccount = await getTokenAccountByMemberByTokenOrFail(overlay, memberId, tokenId)
Expand Down Expand Up @@ -515,7 +515,7 @@
}

const token = await overlay.getRepository(CreatorToken).getByIdOrFail(tokenId.toString())
const sale = await overlay.getRepository(Sale).getByIdOrFail(token.currentSaleId!)

Check warning on line 518 in src/mappings/token/index.ts

View workflow job for this annotation

GitHub Actions / Local build, linting and formatting (ubuntu-latest, 16.x)

Forbidden non-null assertion
sale.tokensSold += amountPurchased

const tx = overlay.getRepository(SaleTransaction).new({
Expand Down Expand Up @@ -574,7 +574,7 @@
},
}: EventHandlerContext<'ProjectToken.UpcomingTokenSaleUpdated'>) {
const token = await overlay.getRepository(CreatorToken).getByIdOrFail(tokenId.toString())
const sale = await overlay.getRepository(Sale).getByIdOrFail(token.currentSaleId!)

Check warning on line 577 in src/mappings/token/index.ts

View workflow job for this annotation

GitHub Actions / Local build, linting and formatting (ubuntu-latest, 16.x)

Forbidden non-null assertion

if (newStart) {
sale.startBlock = newStart
Expand Down Expand Up @@ -692,13 +692,13 @@
export async function processAmmDeactivatedEvent({
overlay,
event: {
asV2002: [tokenId, , burnedAmount],

Check warning on line 695 in src/mappings/token/index.ts

View workflow job for this annotation

GitHub Actions / Local build, linting and formatting (ubuntu-latest, 16.x)

'burnedAmount' is defined but never used
},
}: EventHandlerContext<'ProjectToken.AmmDeactivated'>) {
const token = await overlay.getRepository(CreatorToken).getByIdOrFail(tokenId.toString())
token.status = TokenStatus.IDLE

const activeAmm = await overlay.getRepository(AmmCurve).getByIdOrFail(token.currentAmmSaleId!)

Check warning on line 701 in src/mappings/token/index.ts

View workflow job for this annotation

GitHub Actions / Local build, linting and formatting (ubuntu-latest, 16.x)

Forbidden non-null assertion
activeAmm.finalized = true

token.currentAmmSaleId = null
Expand Down Expand Up @@ -737,12 +737,12 @@
},
}: EventHandlerContext<'ProjectToken.TokenSaleFinalized'>) {
const token = await overlay.getRepository(CreatorToken).getByIdOrFail(tokenId.toString())
const sale = await overlay.getRepository(Sale).getByIdOrFail(token.currentSaleId!)

Check warning on line 740 in src/mappings/token/index.ts

View workflow job for this annotation

GitHub Actions / Local build, linting and formatting (ubuntu-latest, 16.x)

Forbidden non-null assertion
sale.finalized = true

const sourceAccount = await overlay
.getRepository(TokenAccount)
.getByIdOrFail(sale.fundsSourceAccountId!)

Check warning on line 745 in src/mappings/token/index.ts

View workflow job for this annotation

GitHub Actions / Local build, linting and formatting (ubuntu-latest, 16.x)

Forbidden non-null assertion
sourceAccount.totalAmount += quantityLeft

token.status = TokenStatus.IDLE
Expand All @@ -757,21 +757,15 @@
}: EventHandlerContext<'ProjectToken.RevenueSplitLeft'>) {
const account = await getTokenAccountByMemberByTokenOrFail(overlay, memberId, tokenId)
account.stakedAmount -= unstakedAmount
const token = await overlay.getRepository(CreatorToken).getByIdOrFail(tokenId.toString())
if (token.currentRevenueShareId) {
// TODO: refactor this as should be true all the times, might be a good idea to panic
const revenueShare = await overlay
.getRepository(RevenueShare)
.getByIdOrFail(token.currentRevenueShareId)
revenueShare.participantsNum -= 1
const qRevenueShareParticipation = (
await overlay
.getRepository(RevenueShareParticipation)
.getManyByRelation('accountId', account.id)
).find((participation) => participation.revenueShareId === revenueShare.id)
if (qRevenueShareParticipation) {
qRevenueShareParticipation.recovered = true
}

const revenueShareParticipation = (
await overlay
.getRepository(RevenueShareParticipation)
.getManyByRelation('accountId', account.id)
).find((participation) => participation.recovered === false)

if (revenueShareParticipation) {
revenueShareParticipation.recovered = true
}
}

Expand All @@ -784,7 +778,7 @@
const token = await overlay.getRepository(CreatorToken).getByIdOrFail(tokenId.toString())
const revenueShare = await overlay
.getRepository(RevenueShare)
.getByIdOrFail(token.currentRevenueShareId!)

Check warning on line 781 in src/mappings/token/index.ts

View workflow job for this annotation

GitHub Actions / Local build, linting and formatting (ubuntu-latest, 16.x)

Forbidden non-null assertion
revenueShare.finalized = true
token.currentRevenueShareId = null
}
Expand Down
2 changes: 1 addition & 1 deletion src/server-extension/resolvers/CreatorToken/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export class TokenResolver {
cumulativeAllocationAmount += share.allocation
}
return {
cumulativeHistoricalAllocation: Number(cumulativeAllocationAmount),
cumulativeHistoricalAllocation: cumulativeAllocationAmount.toString(),
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/server-extension/resolvers/CreatorToken/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export class GetCumulativeHistoricalShareAllocationArgs {

@ObjectType()
export class GetCumulativeHistoricalShareAllocationResult {
@Field(() => Int, { nullable: false })
cumulativeHistoricalAllocation!: number
@Field(() => String, { nullable: false })
cumulativeHistoricalAllocation!: string
}

@ArgsType()
Expand Down
76 changes: 55 additions & 21 deletions src/utils/offchainState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { createLogger } from '@subsquid/logger'
import assert from 'assert'
import { createParseStream, createStringifyStream } from 'big-json'
import fs from 'fs'
import { snakeCase } from 'lodash'
import path from 'path'
import { EntityManager } from 'typeorm'
import { EntityManager, ValueTransformer } from 'typeorm'
import * as model from '../model'
import {
AccountNotificationPreferences,
Expand Down Expand Up @@ -35,7 +36,7 @@ type ClassConstructors<T> = {
type ExportedStateMap = {
[K in keyof ClassConstructors<typeof model>]?:
| true
| (keyof SnakeCaseKeys<InstanceType<ClassConstructors<typeof model>[K]>>)[]
| (keyof InstanceType<ClassConstructors<typeof model>[K]>)[]
}

const exportedStateMap: ExportedStateMap = {
Expand All @@ -59,17 +60,17 @@ const exportedStateMap: ExportedStateMap = {
EmailDeliveryAttempt: true,
Token: true,
NextEntityId: true,
Channel: ['is_excluded', 'video_views_num', 'follows_num', 'ypp_status', 'channel_weight'],
Video: ['is_excluded', 'views_num'],
Comment: ['is_excluded'],
OwnedNft: ['is_featured'],
VideoCategory: ['is_supported'],
Channel: ['isExcluded', 'videoViewsNum', 'followsNum', 'yppStatus', 'channelWeight'],
Video: ['isExcluded', 'viewsNum'],
Comment: ['isExcluded'],
OwnedNft: ['isFeatured'],
VideoCategory: ['isSupported'],
}

type ExportedData = {
[K in keyof typeof exportedStateMap]?: {
type: 'insert' | 'update'
values: Record<string, unknown>[]
values: InstanceType<ClassConstructors<typeof model>[K]>[]
}
}

Expand All @@ -88,20 +89,20 @@ function migrateExportDataToV300(data: ExportedData): ExportedData {
id: `${V2_MIGRATION_USER_PREFIX}${uniqueId()}`,
isRoot: false,
}
data.User = { type: 'insert', values: [migrationUser] }
data.User = { type: 'insert', values: [migrationUser as model.User] }
const replaceIpWithUserId = (v: Record<string, unknown>) => {
delete v.ip
v.userId = migrationUser.id
}
data.VideoViewEvent?.values.forEach(replaceIpWithUserId)
data.Report?.values.forEach(replaceIpWithUserId)
data.NftFeaturingRequest?.values.forEach(replaceIpWithUserId)
data.VideoViewEvent?.values.forEach(replaceIpWithUserId as any)
data.Report?.values.forEach(replaceIpWithUserId as any)
data.NftFeaturingRequest?.values.forEach(replaceIpWithUserId as any)

// We don't migrate channel follows from v2, because in v3
// an account is required in order to follow a channel
delete data.ChannelFollow
data.Channel?.values.forEach((v) => {
v.follows_num = 0
v.followsNum = 0
})

return data
Expand All @@ -111,8 +112,6 @@ function migrateExportDataToV320(data: ExportedData): ExportedData {
data.Account?.values.forEach((account) => {
// account will find himself with all notification pref. enabled by default
account.notificationPreferences = defaultNotificationPreferences()
// referrer channel id is set to null
account.referrerChannelId = null
})

// all channels will start as unverified because they are re-synched from mappings
Expand Down Expand Up @@ -197,7 +196,10 @@ export class OffchainState {
? await em
.getRepository(entityName)
.createQueryBuilder()
.select(['id', ...(fields as unknown as string)])
.select([
'id',
...fields.map((field) => `${snakeCase(String(field))} AS "${String(field)}"`),
])
.getRawMany()
: await em.getRepository(entityName).find({})
if (!values.length) {
Expand Down Expand Up @@ -234,8 +236,36 @@ export class OffchainState {
return parseInt(major) * (1000 * 1000) + parseInt(minor) * 1000 + parseInt(patch)
}

private transformJsonbProperties(data: ExportedData, em: EntityManager): ExportedData {
// construct proper JSONB objects from raw data
return Object.fromEntries(
Object.entries(data).map(([entityName, { type, values }]) => {
const metadata = em.connection.getMetadata(entityName)
const jsonbColumns = metadata.columns.filter((c) => c.type === 'jsonb')

values = (values as any[]).map((value) => {
jsonbColumns.forEach((column) => {
const propertyName = column.propertyName
const transformer = column.transformer as ValueTransformer | undefined
if (value[propertyName] && transformer) {
const rawValue = value[propertyName]
const transformedValue = transformer.from(rawValue)
value[propertyName] = transformedValue
}
})
return value
})

return [entityName, { type, values }]
})
)
}

public prepareExportData(exportState: ExportedState, em: EntityManager): ExportedData {
let { data } = exportState

data = this.transformJsonbProperties(data, em)

Object.entries(this.migrations)
.sort(([a], [b]) => this.versionToNumber(a) - this.versionToNumber(b)) // sort in increasing order
.forEach(([version, fn]) => {
Expand All @@ -250,7 +280,7 @@ export class OffchainState {
private async importNextEntityIdCounters(
overlay: EntityManagerOverlay,
entityName: string,
data: Record<string, unknown>[]
data: model.NextEntityId[]
) {
const em = overlay.getEm()
assert(entityName === 'NextEntityId')
Expand Down Expand Up @@ -297,7 +327,7 @@ export class OffchainState {
const fieldTypes = Object.fromEntries(
fieldNames.map((fieldName) => {
const metaType = meta.columns.find(
(c) => c.databaseNameWithoutPrefixes === fieldName
(c) => c.databaseNameWithoutPrefixes === snakeCase(fieldName)
)?.type
return [fieldName, metaType === String ? 'text' : metaType]
})
Expand All @@ -314,7 +344,7 @@ export class OffchainState {
`UPDATE "${meta.tableName}"
SET ${fieldNames
.filter((f) => f !== 'id')
.map((f) => `"${f}" = "data"."${f}"`)
.map((f) => `"${snakeCase(f)}" = "data"."${f}"`)
.join(', ')}
FROM (
SELECT
Expand All @@ -326,7 +356,7 @@ export class OffchainState {
.join(', ')}
) AS "data"
WHERE "${meta.tableName}"."id" = "data"."id"`,
fieldNames.map((fieldName) => batch.map((v) => v[fieldName]))
fieldNames.map((fieldName) => batch.map((v) => v[fieldName as keyof typeof v]))
)
}
} else {
Expand All @@ -344,7 +374,11 @@ export class OffchainState {

// UPSERT operation specifically for NextEntityId
if (entityName === 'NextEntityId') {
await this.importNextEntityIdCounters(overlay, entityName, batch)
await this.importNextEntityIdCounters(
overlay,
entityName,
batch as model.NextEntityId[]
)
} else {
await em.getRepository(entityName).insert(batch)
}
Expand Down
Loading