Skip to content
Open
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
49 changes: 30 additions & 19 deletions packages/networks/src/chains/assethub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const custom = {
dot: { Concrete: { parents: 1, interior: 'Here' } },
usdt: { Concrete: { parents: 0, interior: { X2: [{ PalletInstance: 50 }, { GeneralIndex: 1984 }] } } },
usdtIndex: 1984,
usdc: { Concrete: { parents: 0, interior: { X2: [{ PalletInstance: 50 }, { GeneralIndex: 1337 }] } } },
usdcIndex: 1337,
eth: {
parents: 2,
interior: {
Expand All @@ -25,6 +27,8 @@ const custom = {
ksm: { Concrete: { parents: 1, interior: 'Here' } },
usdt: { Concrete: { parents: 0, interior: { X2: [{ PalletInstance: 50 }, { GeneralIndex: 1984 }] } } },
usdtIndex: 1984,
usdc: { Concrete: { parents: 0, interior: { X2: [{ PalletInstance: 50 }, { GeneralIndex: 1337 }] } } },
usdcIndex: 1337,
eth: {
parents: 2,
interior: {
Expand All @@ -42,25 +46,32 @@ const custom = {
},
}

const getInitStorages = (config: typeof custom.assetHubPolkadot | typeof custom.assetHubKusama) => ({
System: {
account: [
[[defaultAccounts.alice.address], { providers: 1, data: { free: 1000e10 } }],
[[defaultAccountsSr25519.alice.address], { providers: 1, data: { free: 1000e10 } }],
],
},
Assets: {
account: [
[[config.usdtIndex, defaultAccounts.alice.address], { balance: 1000e6 }], // USDT
],
},
ForeignAssets: {
account: [
[[config.eth, defaultAccounts.alice.address], { balance: 10n ** 18n }], // 1 ETH
[[config.eth, '13cKp89Msu7M2PiaCuuGr1BzAsD5V3vaVbDMs3YtjMZHdGwR'], { balance: 10n ** 20n }], // 100 ETH for Sibling 2000
],
},
})
const getInitStorages = (config: typeof custom.assetHubPolkadot | typeof custom.assetHubKusama) => {
return {
System: {
account: [
[[defaultAccounts.alice.address], { providers: 1, data: { free: 1000e10 } }],
[[defaultAccountsSr25519.alice.address], { providers: 1, data: { free: 1000e10 } }],
],
},
Assets: {
account: [
[[config.usdtIndex, defaultAccounts.alice.address], { balance: 1000e6 }], // USDT
[[config.usdcIndex, '5Eg2fntPdLr67jPWMPa9MK7ywRHJ8rAtsgoppSKH8X2bgiiV'], { balance: 5000000e6 }], // 5M USDC for people chain sovereign account
],
},
ForeignAssets: {
account: [
[[config.eth, defaultAccounts.alice.address], { balance: 10n ** 18n }], // 1 ETH
[[config.eth, '13cKp89Msu7M2PiaCuuGr1BzAsD5V3vaVbDMs3YtjMZHdGwR'], { balance: 10n ** 20n }], // 100 ETH for Sibling 2000
],
},
PolkadotXcm: {
// Clear XCM version notifications to avoid interference with test messages
$removePrefix: ['versionNotifyTargets', 'versionNotifiers'],
},
}
}

export const assetHubPolkadot = defineChain({
name: 'assetHubPolkadot',
Expand Down
4 changes: 3 additions & 1 deletion packages/networks/src/chains/people.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { defineChain } from '../defineChain.js'
const custom = {
peoplePolkadot: {
dot: { Concrete: { parents: 1, interior: 'Here' } },
usdcIndex: 1337,
},
peopleKusama: {
ksm: { Concrete: { parents: 1, interior: 'Here' } },
usdcIndex: 1337,
},
}

Expand All @@ -22,7 +24,7 @@ const bobRegistrar = {
fields: 0,
}

const getInitStorages = (_config: typeof custom.peoplePolkadot | typeof custom.peopleKusama) => ({
const getInitStorages = (config: typeof custom.peoplePolkadot | typeof custom.peopleKusama) => ({
System: {
account: [
[[defaultAccounts.alice.address], { providers: 1, data: { free: 1000e10 } }],
Expand Down
36 changes: 36 additions & 0 deletions packages/polkadot/src/helpers/migration-constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Constants and expected values for migration testing
*/

export const MIGRATION_CONSTANTS = {
EXPECTED_INITIAL_PEOPLE_COUNT: 3,

EXPECTED_CHUNKS_COUNT: 512,

EXPECTED_DESIGN_FAMILIES_COUNT: 2,

EXPECTED_GAME_SCHEDULES_COUNT: 33,

EXPECTED_ONBOARDING_SIZE: 10,

MAX_MIGRATION_BLOCKS: 30,

PRIVACY_VOUCHER_VALUE_REFERRED: 80000000000,
PRIVACY_VOUCHER_VALUE_REFERRER: 20000000000,

MAX_ON_POLL_BLOCKS: 10,

EXPECTED_POT_FUNDING_AMOUNT: 1000000,

MOB_RULE_PAYOUT: {
AMOUNT_PER_ROUND: 1000,
COUNT: 10,
PERIOD_BLOCKS: 100800, // 1 week in blocks (assuming 6 seconds block time)
},

SCORE_PAYOUT: {
AMOUNT_PER_ROUND: 500,
COUNT: 5,
DURATION_BLOCKS: 201600, // 2 weeks in blocks (assuming 6 seconds block time)
},
} as const
191 changes: 191 additions & 0 deletions packages/polkadot/src/helpers/people-polkadot-transaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import type { Client } from '@e2e-test/networks'

import { ApiPromise, type WsProvider } from '@polkadot/api'
import type { SubmittableExtrinsic } from '@polkadot/api/types'
import type { KeyringPair } from '@polkadot/keyring/types'

/**
* Transaction extensions configuration for People Polkadot runtime.
*/
export const PEOPLE_POLKADOT_TX_EXTENSIONS = {
VerifyMultiSignature: { extrinsic: { verifyMultiSignature: 'u8' }, payload: {} },
AsPerson: { extrinsic: { asPerson: 'u8' }, payload: {} },
AsProofOfInkParticipant: { extrinsic: { asProofOfInkParticipant: 'Option<Null>' }, payload: {} },
ProvideForVoucherClaimer: { extrinsic: { provideForVoucherClaimer: 'Null' }, payload: {} },
ScoreAsParticipant: { extrinsic: { scoreAsParticipant: 'u8' }, payload: {} },
GameAsInvited: { extrinsic: { gameAsInvited: 'u8' }, payload: {} },
RestrictOrigins: { extrinsic: { restrictOrigins: 'bool' }, payload: {} },
CheckNonZeroSender: { extrinsic: {}, payload: {} },
CheckWeight: { extrinsic: {}, payload: {} },
} as const

/**
* Transaction extensions order for People Polkadot runtime.
* This must match the exact order from the runtime metadata.
*/
export const PEOPLE_POLKADOT_EXTENSION_ORDER = [
'VerifyMultiSignature',
'AsPerson',
'AsProofOfInkParticipant',
'ProvideForVoucherClaimer',
'ScoreAsParticipant',
'GameAsInvited',
'RestrictOrigins',
'CheckNonZeroSender',
'CheckSpecVersion',
'CheckTxVersion',
'CheckGenesis',
'CheckMortality',
'CheckNonce',
'CheckWeight',
'ChargeTransactionPayment',
'CheckMetadataHash',
] as const

/**
* Default values for custom transaction extensions
*/
export interface CustomExtensionOptions {
verifyMultiSignature?: number
asPerson?: number
asProofOfInkParticipant?: null
provideForVoucherClaimer?: null
scoreAsParticipant?: number
gameAsInvited?: number
restrictOrigins?: boolean
}

/**
* Standard transaction options
*/
export interface TransactionOptions {
nonce?: number
tip?: number
era?: any
customExtensions?: CustomExtensionOptions
}

/**
* Creates an ApiPromise instance configured for People Polkadot custom transaction extensions
*/
export async function createPeoplePolkadotApi(client: Client): Promise<ApiPromise> {
const provider = client.ws as unknown as WsProvider

const api = await ApiPromise.create({
provider,
signedExtensions: [...PEOPLE_POLKADOT_EXTENSION_ORDER],
userExtensions: PEOPLE_POLKADOT_TX_EXTENSIONS,
types: {},
})

await api.isReady

// Force the registry to use our exact order
;(api.registry as any).setSignedExtensions?.(
PEOPLE_POLKADOT_EXTENSION_ORDER as any,
PEOPLE_POLKADOT_TX_EXTENSIONS as any,
)

return api
}

/**
* Creates signing options for People Polkadot transactions with custom extensions
*/
export function createSigningOptions(api: ApiPromise, nonce: number, options: TransactionOptions = {}) {
const customExtensions = options.customExtensions || {}

return {
verifyMultiSignature: customExtensions.verifyMultiSignature ?? 1, // MultiSignature::Sr25519
asPerson: customExtensions.asPerson ?? 0,
asProofOfInkParticipant: customExtensions.asProofOfInkParticipant ?? null, // None
provideForVoucherClaimer: customExtensions.provideForVoucherClaimer ?? null, // unit
scoreAsParticipant: customExtensions.scoreAsParticipant ?? 0,
gameAsInvited: customExtensions.gameAsInvited ?? 0,
restrictOrigins: customExtensions.restrictOrigins ?? false,

// Standard extensions
era: options.era ?? api.registry.createType('ExtrinsicEra', 0), // IMMORTAL
blockHash: api.genesisHash,
genesisHash: api.genesisHash,
nonce,
tip: options.tip ?? 0,
}
}

/**
* Submits a transaction to People Polkadot with custom transaction extensions and automatic block production
*/
export async function submitPeoplePolkadotTransaction(
client: Client,
transaction: SubmittableExtrinsic<'promise'>,
signer: KeyringPair,
options: TransactionOptions = {},
): Promise<boolean> {
const api = await createPeoplePolkadotApi(client)

const nonce = options.nonce ?? (await api.rpc.system.accountNextIndex(signer.address))
const nonceNumber = typeof nonce === 'number' ? nonce : nonce.toNumber()

const signOpts = createSigningOptions(api, nonceNumber, options)

return new Promise<boolean>((resolve, reject) => {
let unsub: (() => void) | undefined

const tx = api.tx[transaction.method.section][transaction.method.method](...transaction.method.args)

tx.signAndSend(signer, signOpts as any, async (result) => {
const { status, events, dispatchError } = result
console.log('[status]', status.type)

await client.dev.newBlock()

if (status.isInBlock) {
console.log('[inBlock] hash=%s', status.asInBlock.toHex())
}

if (events?.length) {
console.log('[events] %d', events.length)
events.forEach(({ event, phase }, idx) => {
console.log(
' #%d phase=%s %s.%s %s',
idx,
phase.toString(),
event.section,
event.method,
JSON.stringify(event.data.toHuman()),
)
})
}

if (dispatchError) {
if ((dispatchError as any).isModule) {
const decoded = api.registry.findMetaError((dispatchError as any).asModule)
console.error('[error] module=%s.%s docs=%s', decoded.section, decoded.name, decoded.docs.join(' '))
unsub?.()
return reject(new Error(`${decoded.section}.${decoded.name}`))
} else {
console.error('[error] %s', dispatchError.toString())
unsub?.()
return reject(new Error(dispatchError.toString()))
}
}

if (status.isFinalized) {
console.log('[finalized] hash=%s', status.asFinalized.toHex())

const ok = events?.some(({ event }) => api.events.system.ExtrinsicSuccess.is(event)) ?? false
unsub?.()
return resolve(ok)
}
})
.then((u) => {
unsub = u
})
.catch((e) => {
console.error('[signAndSend.catch]', e)
unsub?.()
reject(e)
})
})
}
28 changes: 28 additions & 0 deletions packages/polkadot/src/helpers/test-keys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Pre-generated Bandersnatch VRF test keys
*/

// Test vectors for VRF and voucher key testing
export const TEST_PUBLIC_KEY = new Uint8Array([
0x94, 0xf5, 0xab, 0x3b, 0xb2, 0xaa, 0x2d, 0x18, 0xa3, 0xc4, 0x62, 0x5a, 0x0c, 0xc5, 0x70, 0xf8, 0x78, 0xf5, 0xf1,
0x31, 0x58, 0x55, 0xaf, 0xe5, 0x8b, 0x51, 0x11, 0x70, 0x3b, 0x7e, 0xf2, 0x48,
])

export const TEST_VRF_SIGNATURE = new Uint8Array([
0xb1, 0x48, 0xd9, 0x6e, 0x85, 0x20, 0x14, 0x58, 0xfa, 0x36, 0xf2, 0x85, 0x0a, 0x01, 0x8c, 0xac, 0x93, 0xb8, 0x59,
0x65, 0x85, 0xd0, 0xde, 0x82, 0x1a, 0xc6, 0xb5, 0xe0, 0x10, 0xa2, 0xd8, 0xd5, 0x8e, 0xbc, 0x81, 0x11, 0xea, 0x81,
0xad, 0xc7, 0x50, 0x02, 0xb3, 0x51, 0x3b, 0x92, 0x63, 0x2b, 0x5d, 0x88, 0x7e, 0x98, 0x2c, 0xae, 0xeb, 0x86, 0x2c,
0xc0, 0x1b, 0xa1, 0x12, 0x3d, 0xac, 0x05, 0xa7, 0xf6, 0x03, 0xb0, 0xa8, 0x7e, 0x9a, 0xaf, 0xa6, 0xe4, 0x0d, 0x6b,
0x11, 0x85, 0x72, 0x23, 0xa6, 0x7d, 0x0a, 0xd1, 0x19, 0x50, 0xf7, 0xf1, 0xd3, 0x7c, 0x04, 0xb8, 0x7e, 0x13, 0x27,
0x16,
])

export const TEST_VOUCHER_KEY_1 = new Uint8Array([
0x76, 0xc7, 0xe3, 0x3e, 0x0d, 0x8a, 0x19, 0x7d, 0x47, 0x47, 0x0d, 0xca, 0x8b, 0xb7, 0x75, 0x56, 0x63, 0x31, 0x5a,
0xf0, 0x00, 0x82, 0x8d, 0xed, 0x1f, 0x97, 0xea, 0x86, 0x08, 0x29, 0x3e, 0xac,
])

export const TEST_VOUCHER_KEY_2 = new Uint8Array([
0x7d, 0xaf, 0x2a, 0xda, 0x76, 0xe7, 0x32, 0xf0, 0x87, 0x1c, 0xf6, 0xaa, 0x82, 0x03, 0x26, 0x33, 0x56, 0x45, 0x71,
0x35, 0xf4, 0x1f, 0x24, 0x52, 0xa1, 0x1a, 0x10, 0x40, 0xe7, 0xa1, 0x22, 0x8d,
])
Loading