diff --git a/cspell.json b/cspell.json index 856043707..b659c059d 100644 --- a/cspell.json +++ b/cspell.json @@ -10,13 +10,11 @@ ], "dictionaries": ["project-words"], "ignorePaths": [ - "**/mod.generated.js", - "**/mod_bg.wasm", - "Cargo.lock", - "deno.lock", + "**/*.wasm", "frame_metadata/raw_erc20_metadata.json", "target", "**/__snapshots__/*.snap", - "codegen/_output" + "**/*.contract", + "examples/smart_contract/metadata.json" ] } diff --git a/deps/std/encoding/base58.ts b/deps/std/encoding/base58.ts index e94d0fdd6..fbe18cd03 100644 --- a/deps/std/encoding/base58.ts +++ b/deps/std/encoding/base58.ts @@ -1 +1 @@ -export * from "https://deno.land/std@0.154.0/encoding/base58.ts" +export * from "https://deno.land/std@0.168.0/encoding/base58.ts" diff --git a/effects/contracts/call.ts b/effects/contracts/call.ts new file mode 100644 index 000000000..05180ed1b --- /dev/null +++ b/effects/contracts/call.ts @@ -0,0 +1,149 @@ +import * as $ from "../../deps/scale.ts" +import * as Z from "../../deps/zones.ts" +import { + $contractsApiCallArgs, + $contractsApiCallResult, + ContractMetadata, +} from "../../frame_metadata/Contract.ts" +import { DeriveCodec, MultiAddress } from "../../frame_metadata/mod.ts" +import { Client } from "../../rpc/mod.ts" +import * as U from "../../util/mod.ts" +import { extrinsic } from "../extrinsic.ts" +import { state } from "../rpc_known_methods.ts" + +export interface CallProps { + sender: MultiAddress + contractAddress: Uint8Array + contractMetadata: ContractMetadata + message: ContractMetadata.Message + args: any[] +} + +export function call>(client: Client_) { + return >(_props: Props) => { + const { + sender, + contractAddress, + contractMetadata, + message, + args, + } = _props as Z.Rec$Access + const $message_ = $message(contractMetadata, message) + const data = Z.ls($message_, message, args).next(([{ $args }, { selector }, args]) => + $args.encode([U.hex.decode(selector), ...args]) + ) + return Z.ls( + stateContractsApiCall(client)({ + sender, + contractAddress, + data, + }), + $message_, + ) + .next(([{ result: { data } }, { $result }]) => $result.decode(data)) + } +} + +export interface CallTxProps { + sender: MultiAddress + contractAddress: Uint8Array + value?: bigint + contractMetadata: ContractMetadata + message: ContractMetadata.Message + args: any[] +} + +export function callTx>(client: Client_) { + return >(_props: Props) => { + const { + sender, + contractAddress, + value, + contractMetadata, + message, + args, + } = _props as Z.Rec$Access + const $message_ = $message(contractMetadata, message) + const data = Z.ls($message_, message, args).next(([{ $args }, { selector }, args]) => + $args.encode([U.hex.decode(selector), ...args]) + ) + const txValue = Z.ls( + stateContractsApiCall(client)({ + sender, + contractAddress, + value, + data, + }), + contractAddress, + value, + data, + ) + .next(([{ gasRequired }, contractAddress, value, data]) => ( + { + type: "call", + dest: MultiAddress.Id(contractAddress), + value: value ?? 0n, + data, + gasLimit: gasRequired, + storageDepositLimit: undefined, + } + )) + return extrinsic(client)({ + sender, + call: Z.rec({ type: "Contracts", value: txValue }), + }) + } +} + +export interface ContractsApiCallProps { + sender: MultiAddress + contractAddress: Uint8Array + value?: bigint + data: Uint8Array +} + +export function stateContractsApiCall>(client: Client_) { + return >(_props: Props) => { + const key = Z.rec(_props as Z.Rec$Access).next( + ({ sender, contractAddress, value, data }) => + U.hex.encode($contractsApiCallArgs.encode([ + sender.value!, // TODO: grab public key in cases where we're not accepting multi? + contractAddress, + value ?? 0n, + undefined, + undefined, + data, + ])), + ) + return state + .call(client)("ContractsApi_call", key) + .next((result) => { + return $contractsApiCallResult.decode(U.hex.decode(result)) + }) + } +} + +interface MessageCodecs { + $args: $.Codec<[Uint8Array, ...unknown[]]> + $result: $.Codec +} + +function $message( + metadata: Z.$, + message: Z.$, +): Z.$ { + return Z.ls(metadata, message).next(([metadata, message]) => { + const deriveCodec = DeriveCodec(metadata.V3.types) + return { + $args: $.tuple( + // message selector + $.sizedUint8Array(U.hex.decode(message.selector).length), + // message args + ...message.args.map((arg) => deriveCodec(arg.type.type)), + ), + $result: message.returnType !== null + ? deriveCodec(message.returnType.type) + : $.constant(null), + } + }) +} diff --git a/effects/contracts/events.ts b/effects/contracts/events.ts new file mode 100644 index 000000000..8b39a5833 --- /dev/null +++ b/effects/contracts/events.ts @@ -0,0 +1,28 @@ +import * as $ from "../../deps/scale.ts" +import * as Z from "../../deps/zones.ts" +import { ContractMetadata, DeriveCodec } from "../../frame_metadata/mod.ts" +import { ExtrinsicEvent } from "../events.ts" + +export function events( + contractMetadata: Z.$, + events: Z.$, +) { + const $events = Z.ls(contractMetadata).next(([contractMetadata]) => { + return $.taggedUnion( + "type", + contractMetadata.V3.spec.events + .map((e) => [ + e.label, + [ + "value", + $.tuple(...e.args.map((a) => DeriveCodec(contractMetadata.V3.types)(a.type.type))), + ], + ]), + ) + }) + return Z.ls(events, $events).next(([events, $events]) => { + return events + .filter((e) => e.event?.type === "Contracts" && e.event?.value?.type === "ContractEmitted") + .map((e) => $events.decode(e.event?.value.data)) + }) +} diff --git a/effects/contracts/instantiate.ts b/effects/contracts/instantiate.ts new file mode 100644 index 000000000..90ff31a33 --- /dev/null +++ b/effects/contracts/instantiate.ts @@ -0,0 +1,62 @@ +import * as Z from "../../deps/zones.ts" +import { + $contractsApiInstantiateArgs, + $contractsApiInstantiateResult, + ContractMetadata, +} from "../../frame_metadata/Contract.ts" +import { MultiAddress } from "../../frame_metadata/mod.ts" +import { Client } from "../../rpc/mod.ts" +import * as U from "../../util/mod.ts" +import { extrinsic } from "../extrinsic.ts" +import { state } from "../rpc_known_methods.ts" + +export interface InstantiateProps { + sender: MultiAddress + code: Uint8Array + constructorMetadata: ContractMetadata.Constructor + salt: Uint8Array +} + +export function instantiate>(client: Client_) { + return >(_props: Props) => { + const { code, constructorMetadata, sender } = _props as Z.Rec$Access + const value = Z.ls(_props.salt, instantiateGasEstimate(client)(_props), constructorMetadata) + .next(([salt, { gasRequired }, { selector }]) => { + // the contract address derived from the code hash and the salt + return { + type: "instantiateWithCode", + value: 0n, + gasLimit: gasRequired, + storageDepositLimit: undefined, + code, + data: U.hex.decode(selector), + salt, + } + }) + return extrinsic(client)({ + sender, + call: Z.rec({ type: "Contracts", value }), + }) + } +} + +export function instantiateGasEstimate>(client: Client_) { + return >(_props: Props) => { + const key = Z.rec(_props as Z.Rec$Access).next( + ({ code, constructorMetadata, sender, salt }) => { + return U.hex.encode($contractsApiInstantiateArgs.encode([ + sender.value!, // TODO: grab public key in cases where we're not accepting multi? + 0n, + undefined, + undefined, + { type: "Upload", value: code }, + U.hex.decode(constructorMetadata.selector), + salt, + ])) + }, + ) + return state + .call(client)("ContractsApi_instantiate", key) + .next((result) => $contractsApiInstantiateResult.decode(U.hex.decode(result))) + } +} diff --git a/effects/contracts/mod.ts b/effects/contracts/mod.ts new file mode 100644 index 000000000..af8dae12e --- /dev/null +++ b/effects/contracts/mod.ts @@ -0,0 +1,3 @@ +export * from "./call.ts" +export * from "./events.ts" +export * from "./instantiate.ts" diff --git a/effects/events.ts b/effects/events.ts index 6bb3be7c8..38db4a321 100644 --- a/effects/events.ts +++ b/effects/events.ts @@ -24,7 +24,7 @@ export function events() + .as() return Z .ls(idx, events) .next(([idx, events]) => { @@ -33,3 +33,8 @@ export function events + phase: { value: number } +} diff --git a/effects/mod.ts b/effects/mod.ts index 8cfd4c3e5..bca36a484 100644 --- a/effects/mod.ts +++ b/effects/mod.ts @@ -1,5 +1,6 @@ export * from "./blockWatch.ts" export * from "./const.ts" +export * as contracts from "./contracts/mod.ts" export * from "./entryRead.ts" export * from "./entryWatch.ts" export * from "./events.ts" diff --git a/effects/rpc_known_methods.ts b/effects/rpc_known_methods.ts index 0092b1452..f83d55729 100644 --- a/effects/rpc_known_methods.ts +++ b/effects/rpc_known_methods.ts @@ -5,6 +5,7 @@ import { rpcCall, rpcSubscription } from "./rpc.ts" // TODO: generate the following? export namespace state { export const getMetadata = rpcCall<[at?: U.HexHash], U.HexHash>("state_getMetadata") + export const call = rpcCall<[method: string, data: U.Hex], U.HexHash>("state_call") export const getStorage = rpcCall< [key: known.StorageKey, at?: U.HexHash], known.StorageData diff --git a/examples/.ignore b/examples/.ignore index 49b58b983..c941fcc58 100644 --- a/examples/.ignore +++ b/examples/.ignore @@ -1,3 +1,4 @@ mod.ts multisig_transfer.ts +smart_contract.ts xcm_teleport_assets.ts diff --git a/examples/smart_contract.ts b/examples/smart_contract.ts new file mode 100644 index 000000000..5c3d64ef9 --- /dev/null +++ b/examples/smart_contract.ts @@ -0,0 +1,175 @@ +// This example requires zombienet-macos/zombienet-linux, polkadot and polkadot-parachain binaries in the PATH + +import * as path from "http://localhost:5646/@local/deps/std/path.ts" +import * as C from "http://localhost:5646/@local/mod.ts" +import * as T from "http://localhost:5646/@local/test_util/mod.ts" +import * as U from "http://localhost:5646/@local/util/mod.ts" + +const configFile = path.join( + path.dirname(path.fromFileUrl(import.meta.url)), + "smart_contract/zombienet.toml", +) +const zombienet = await T.zombienet.start(configFile) +const client = zombienet.clients.byName["collator01"]! + +const salt = Uint8Array.from(Array.from([0, 0, 0, 0]), () => Math.floor(Math.random() * 16)) + +const [code, metadataRaw] = await Promise.all([ + await Deno.readFile("examples/smart_contract/flipper.wasm"), + await Deno.readTextFile("examples/smart_contract/metadata.json"), +]) +const metadata = C.M.ContractMetadata.normalize(JSON.parse(metadataRaw)) +const constructorMetadata = metadata.V3.spec.constructors.find((c) => c.label === "default")! + +class ExtrinsicFailed extends Error { + override readonly name = "ExtrinsicFailedError" + constructor( + override readonly cause: { + event?: Record + phase: { value: number } + }, + ) { + super() + } +} + +const tx = C.contracts.instantiate(client)({ + code, + constructorMetadata, + salt, + sender: T.alice.address, +}).signed(T.alice.sign) +const finalizedIn = tx.watch(({ end }) => (status) => { + if (typeof status !== "string" && (status.inBlock ?? status.finalized)) { + return end(status.inBlock ?? status.finalized) + } else if (C.rpc.known.TransactionStatus.isTerminal(status)) { + return end(new Error()) + } + return +}) +const contractAddress = U.throwIfError( + await C + .events(tx, finalizedIn) + .next((events) => { + const extrinsicFailedEvent = events.find((e) => + e.event?.type === "System" && e.event?.value?.type === "ExtrinsicFailed" + ) + if (extrinsicFailedEvent) { + return new ExtrinsicFailed(extrinsicFailedEvent) + } + const event = events.find((e) => + e.event?.type === "Contracts" && e.event?.value?.type === "Instantiated" + ) + return event?.event?.value.contract as Uint8Array + }) + .run(), +) + +const prefix = U.throwIfError(await C.const(client)("System", "SS58Prefix").access("value").run()) +console.log("Deployed Contract address", U.ss58.encode(prefix, contractAddress)) + +const flipperContract = new C.fluent.Contract(client, metadata, contractAddress) +console.log( + ".get", + await flipperContract.call({ + sender: T.alice.address, + messageLabel: "get", + args: [], + }).run(), +) +console.log( + "block hash and events", + U.throwIfError( + await flipperContract.callTx({ + sender: T.alice.address, + args: [], + sign: T.alice.sign, + messageLabel: "flip", + }).run(), + )[0], +) +console.log( + ".get", + await flipperContract.call({ + sender: T.alice.address, + messageLabel: "get", + args: [], + }).run(), +) +console.log( + ".get_count", + await flipperContract.call({ sender: T.alice.address, messageLabel: "get_count", args: [] }) + .run(), +) +console.log( + ".inc block hash", + U.throwIfError( + await flipperContract.callTx({ + sender: T.alice.address, + messageLabel: "inc", + args: [], + sign: T.alice.sign, + }).run(), + )[0], +) +console.log( + ".inc block hash", + U.throwIfError( + await flipperContract.callTx({ + sender: T.alice.address, + messageLabel: "inc", + args: [], + sign: T.alice.sign, + }).run(), + )[0], +) +console.log( + ".get_count", + await flipperContract.call({ sender: T.alice.address, messageLabel: "get_count", args: [] }) + .run(), +) +console.log( + ".inc_by(3) block hash", + U.throwIfError( + await flipperContract.callTx({ + sender: T.alice.address, + messageLabel: "inc_by", + args: [3], + sign: T.alice.sign, + }).run(), + )[0], +) +console.log( + ".get_count", + await flipperContract.call({ sender: T.alice.address, messageLabel: "get_count", args: [] }) + .run(), +) +console.log( + ".inc_by_with_event(3) contract events", + U.throwIfError( + await flipperContract.callTx({ + sender: T.alice.address, + messageLabel: "inc_by_with_event", + args: [3], + sign: T.alice.sign, + }).run(), + )[2], +) +console.log( + ".method_returning_tuple(2,true)", + await flipperContract.call({ + sender: T.alice.address, + messageLabel: "method_returning_tuple", + args: [2, true], + }).run(), +) +console.log( + ".method_returning_struct(3,false)", + await flipperContract.call({ + sender: T.alice.address, + messageLabel: "method_returning_struct", + args: [3, false], + }).run(), +) + +await zombienet.close() diff --git a/examples/smart_contract/flipper.contract b/examples/smart_contract/flipper.contract new file mode 100644 index 000000000..6c62caecb --- /dev/null +++ b/examples/smart_contract/flipper.contract @@ -0,0 +1 @@ +{"source":{"hash":"0x1e3986af05daee058d114887d78d251e7bad3700b7e5aa01741572162d7b3d85","language":"ink! 3.4.0","compiler":"rustc 1.68.0-nightly","wasm":"0x0061736d01000000014e0d60037f7f7f017f60027f7f017f60027f7f0060037f7f7f0060047f7f7f7f0060057f7f7f7f7f0060017f0060000060047f7f7f7f017f60017f017e60067f7f7f7f7f7f0060017f017f6000017f02ef010a057365616c30127365616c5f64656275675f6d6573736167650001057365616c30127365616c5f6465706f7369745f6576656e740004057365616c30107365616c5f7365745f73746f726167650003057365616c30107365616c5f6765745f73746f726167650000057365616c300a7365616c5f696e7075740002057365616c300b7365616c5f72657475726e0003057365616c30147365616c5f686173685f626c616b65325f3235360003057365616c300b7365616c5f63616c6c65720002057365616c30167365616c5f76616c75655f7472616e73666572726564000203656e76066d656d6f727902010210034d4c0004030303030302000b0203020206010202020202030c0207060701050202040503010000030101000607020601090504010101050804080503010103000005040804010101010a01040a04040501700110100501000608017f01418080040b071102066465706c6f7900210463616c6c00230915010041010b0f1843444f3a364c4d35512d2f304e370a916a4c2b01017f037f2002200346047f200005200020036a200120036a2d00003a0000200341016a21030c010b0b0b1400200020012002200341ac9b044180800410530b5001017f230041206b220324002003410c6a4101360200200341146a4100360200200341a8a004360210200341003602002003200136021c200320003602182003200341186a360208200320021019000b3901017f230041106b22032400200341086a410020012002100a200328020c21012000200328020836020020002001360204200341106a24000b950202047f037e230041d0006b22032400200341306a2204200241186a290000370300200341286a2205200241106a290000370300200341206a2206200241086a2900003703002003420137033820032002290000370318200341aea404360240200342808001370244200341106a200341406b22022001100e200341186a220120032802102003280214100220032003290318220720032903387c22083703182006200629030022092007200856ad7c22073703002005200529030022082007200954ad7c2207370300200420042903002007200854ad7c37030020034201370338200341aea404360240200342808001370244200341086a20022000100f20012003280208200328020c1002200341d0006a24000b5602017f017e230041206b220324002001290200210420034100360218200320043703102002200341106a101520012003290310370200200341086a20012003280218101e20002003290308370300200341206a24000b5602017f017e230041206b220324002001290200210420034100360218200320043703102002200341106a101320012003290310370200200341086a20012003280218101e20002003290308370300200341206a24000b5401027f230041106b220224002002410036020c200020012002410c6a41041011047f410205200228020c210341022001101241ff0171220141017120014102461b0b3a000420002003360200200241106a24000b6001047f230041106b22032400200028020422042002492205450440200341086a41002002200028020022061052200120022003280208200328020c41b4a304102920032002200420061052200020032903003702000b200341106a240020050b4001017f230041106b22012400200141003a000f20002001410f6a41011011047f4102054101410220012d000f22004101461b410020001b0b200141106a24000b2601017f230041106b220224002002200036020c20012002410c6a41041014200241106a24000b6701037f230041106b220324002000280208220420026a2205200449044041f09b04411c41ac9d04100b000b200341086a200420052000280200200028020441bc9d0410502003280208200328020c2001200241cc9d04102920002005360208200341106a24000b2601017f230041106b22022400200220003a000f20012002410f6a41011014200241106a24000b3d01017f230041106b22022400200241086a20014180800141aea404100a200228020c21012000200228020836020020002001360204200241106a24000b5201017f230041206b220124002001410c6a4101360200200141146a4101360200200141a8a004360208200141003602002001410136021c200120003602182001200141186a3602102001419c84041019000b910101017f230041306b22022400200241146a41013602002002411c6a4101360200200241a8a0043602102002410036020820024102360224200220002d0000410274220041fca3046a28020036022c200220004190a4046a280200360228200141046a28020021002002200241206a3602182002200241286a36022020012802002000200241086a1046200241306a24000b840301037f230041206b22032400200341013a00182003200136021420032000360210200341b08b0436020c200341a8a004360208230041406a220224002002200341086a36020c2002410436022420022002410c6a360220410021004104210402400240024002400240024003402000200441b09c046a2802006a22012000490d0120012100200441086a22044114470d000b4100210041012104024020014110490d002001200120016a22034b200345720d0020034100480d022002200310342003210020022802002204450d060b2002410036021820022004360214200220003602102002410136023c20024102360234200241b09c04360230200241003602282002200241206a360238200241106a200241286a102b0d0241aca4042d000045044041ada4042d00004101710d060b2002280214200228021810004109470d030c040b41d08504411c418c9b04100b000b1033000b41d087044133200241286a4194860441f088041025000b41aca40441013a00000b41ada40441013a00000b000b0a0020012000412010140b4801027f230041106b220224002002410036020c024020012002410c6a41041011450440200228020c21010c010b410121030b2000200136020420002003360200200241106a24000b4701017f230041106b220224002002410036020c024020012002410c6a410410114504402000200228020c360001200041003a00000c010b200041013a00000b200241106a24000b0b004100200020011005000b4501017f2002200128020422034b0440418c9c04412341fc9d04100b000b2001200320026b36020420012001280200220120026a36020020002002360204200020013602000b6c02027f027e230041206b22002400200041086a220142003703002000420037030020004110360214200020003602102000411036021c20002000411c6a1008200041106a200028021c10202001290300210220002903002103200041206a2400410541042002200384501b0b3701017f230041106b22022400200241086a410020012000280200200028020441f49e04105020002002290308370200200241106a24000bd40301057f230041306b220024002000027f02400240101f41ff0171410546044020004180800136022c200041aea404360228200041286a1022200020002903283703082000200041086a101c20002d00000d022000280001220141187621022001411076210320014108762104027f200141ff01712201419b01470440200141ed0147200441ff017141cb004772200341ff0171419d0147720d0441022002411b460d011a0c040b200441ff017141ae0147200341ff0171419d014772200241de0047720d03200041086a101241ff017122014102460d0320014101710b2101101f41ff01712102024002402001410247044020024105460d010c040b20024105470d03200041206a4200370300200041186a4200370300200041106a42003703002000420037030841004100200041086a100d0c010b200041206a4200370300200041186a4200370300200041106a42003703002000420037030841002001200041086a100d0b200041306a24000f0b200041043a0008200041086a1017000b41040c010b41030b3a0000200041146a41013602002000411c6a4101360200200041f48404360210200041003602082000410136022c2000200041286a36021820002000360228200041086a419c84041019000b3301017f230041106b220124002001200028020436020c20002802002001410c6a10042000200128020c1020200141106a24000b9e1502067f047e23004190026b220024000240024002402000027f027f0240101f41ff0171220141054604402000418080013602f401200041aea4043602f001200041f0016a1022200020002903f00137039801200041d0016a20004198016a101c024020002d00d0010d0020002800d10122044118762101200441107621022004410876210302400240200441ff01712204411d4704400240024002402004412f470440200441dc00460d02200441e300470440200441b501460d06200441bb01460d04200441d501460d07200441db01460d02200441fe0147200341ff017141db004772200241ff017141d80147200141ea014772720d08200041e0006a20004198016a101b20002802600d08410721022000280264220141807e710c0b0b200341ff0171413a47200241ff017141a5014772200141d10047720d07410021014100210241000c0a0b200341ff017141860147200241ff017141db004772200141d90147720d06410121020c080b200341ff017141c80047200241ff017141f90047722001410e47720d05200041d0006a20004198016a10104102210220002d005422014102460d05200141017121052000280250220141807e710c080b200341ff017141b30147200241ff017141e2014772200141d00147720d04200041d8006a20004198016a101020002d005c22014102460d0420014101712105410321022000280258220141807e710c070b200241ff0171200341ff0171412047722001413a47720d03410421020c050b200341ff0171413247200241ff017141e10047722001419f0147720d02410521020c040b200341ff017141d70147200241ff017141b4014772200141f00147720d01410621020c030b200341ff017141ce0047200241ff017141e70147722001411c47720d00200041e8006a20004198016a101b20002802680d0041082102200028026c220141807e710c030b41030c030b200020013a00980120004198016a1017000b4100210141000b2103200041a0016a4200370300200041a8016a4200370300200041b0016a42003703002000420037039801200042013703b8012000418080013602d401200041aea4043602d00102400240024020004198016a200041d0016a10240e0400040401040b200020002903d0013703f001200041f0016a101241ff017122044102460d0420002903b8012106200042013703b8012000200620002903980122077c220637039801200020002903a00122082006200754ad7c22063703a001200020002903a80122072006200854ad7c22063703a801200020002903b0012006200754ad7c3703b0012000418080013602d401200041aea4043602d001024020004198016a200041d0016a10240e0400040401040b200020002903d0013703f001200041c8006a200041f0016a101b2000280248450d010c040b230041106b220124002001411736020c200141bc8104360208230041206b220024002000410c6a4101360200200041146a4101360200200041a8a004360208200041003602002000410236021c2000200141086a3602182000200041186a360210200041d481041019000b200141ff01712003722103200028024c21012000200441004722043a0074200020013602700240027f024002400240024002400240024002400240024002400240200241016b0e080706060504030200010b101f41ff01714105470d0c200041f0006a20031026200041b0016a22014200370300200041a8016a22024200370300200041a0016a220342003703002000420037039801200041203602f401200020004198016a22043602f001200041203602d0012004200041d0016a1007200041f0016a220420002802d001102020004190016a2001290300220637030020004188016a2002290300220737030020004180016a200329030022083703002000200029039801220937037820002802702101200041a5016a2008370000200041ad016a2007370000200041b5016a2006370000200041013a009c0120002001360298012000200937009d01200041406b41001016200041003602f801200020002903403703f00120044104102720002802f8012202418180014f0d08200041386a20024180800141aea4041028200041003602c80120002903382106200041003602f801200020063703f001200041f0016a220341001027200341a8a00441001014200341e0830441141014200020002903f0013703c001200041306a200041c0016a20002802f801101e2000280230210420002802342103200041e8016a4200370300200041e0016a4200370300200041d8016a4200370300200042003703d0010240200341214f044020004188026a420037030020004180026a4200370300200041f8016a4200370300200042003703f00120042003200041f0016a22031006200041206a4120200041d0016a100c200028022020002802242003412041dc820410290c010b200041286a2003200041d0016a100c2000280228200028022c2004200341cc820410290b200041186a20021016200041003602f801200020002903183703f001200041d0016a200041f0016a101a2002200220002802f8016a22034b0d092000428080013702f401200041aea4043602f001200041106a200041f0016a22022003101e200041d8016a200041f8016a2802002203360200200020002903f00122063703d001200028021421042000280210200041c8016a2003360200200020063703c001200041003602f801200020063703f00120024100102720024101102720004198016a4105722002101a20002802980120021013200020002903f0013703c001200041086a200041c0016a20002802f801101e20042000280208200028020c100120002d00740c0b0b101f41ff01714105460d060c0b0b101f41ff01714105470d0a200041f0006a200310260c080b101f41ff01714105470d09200041f0006a417f10260c070b101f41ff01714105470d08200041f0006a410110260c060b101f41ff01714105470d07230041206b22002400200041aea404360210200042808001370214200041086a200041106a2001100f0c0b0b101f41ff01714105470d06230041206b22012400200141aea404360210200142808001370214230041206b22002400200141106a2202290200210620004100360218200020063703102003200041106a2203101320052003101520022000290310370200200041086a20022000280218101e200141086a2000290308370300200041206a24002001280208200128020c101d000b101f41ff01714105470d05230041206b22002400200041aea404360210200042808001370214200041086a200041106a2004100e0c090b2004450c030b20024180800141ec9d04102a000b41f08204411c41d08304100b000b2000280270210120002d00740b21022001200241ff017141004741ac8404100d20004190026a24000f0b41040b3a00d001200041a4016a4101360200200041ac016a4101360200200041a085043602a0012000410036029801200041013602f4012000200041f0016a3602a8012000200041d0016a3602f00120004198016a419c84041019000b200041fc016a410136020020004184026a4100360200200041b883043602f801200041a8a00436028002200041003602f001200041f0016a41c083041019000b200041003a00f00141a180044127200041f0016a418c830441ac81041025000b2000280208200028020c101d000b5401017f230041106b220224002002200128020436020c200020012802002002410c6a100321002001200228020c1020410c21012000410b4d0440200041027441cca3046a28020021010b200241106a240020010b860101017f230041406a220524002005200136020c200520003602082005200336021420052002360210200541246a41023602002005412c6a41023602002005413c6a4103360200200541e48b0436022020054100360218200541023602342005200541306a3602282005200541106a3602382005200541086a360230200541186a20041019000b3201017f20014100482001200028020022016a220220014873450440200020023602000f0b41f08204411c41a88504100b000ba10101027f20002802082202200028020422034904402000200241016a360208200028020020026a20013a00000f0b230041306b220024002000200336020420002002360200200041146a41023602002000411c6a41023602002000412c6a4105360200200041848b0436021020004100360208200041053602242000200041206a360218200020003602282000200041046a360220200041086a41dc9d041019000b1400200020012002200341ac9b0441c09b0410530b8501002001200346044020002002200110091a0f0b230041306b220024002000200336020420002001360200200041146a41033602002000411c6a41023602002000412c6a4105360200200041f4940436021020004100360208200041053602242000200041206a360218200020003602282000200041046a360220200041086a20041019000b0e0020002001200241bc910410540b5501017f230041206b2202240020022000360204200241186a200141106a290200370300200241106a200141086a29020037030020022001290200370308200241046a41b88504200241086a102c200241206a24000bee0301057f230041406a22032400200341033a003820034280808080800437033020034100360228200341003602202003200136021c20032000360218027f0240024020022802002201450440200241146a28020022004103742105200041ffffffff017121072002280210210441002101034020012005460d02200228020820016a220041046a28020022060440200328021820002802002006200328021c28020c1100000d040b200141086a2101200428020020042802042106200441086a2104200341186a2006110100450d000b0c020b200228020422074105742100200741ffffff3f71210703402000450d01200228020820046a220541046a28020022060440200328021820052802002006200328021c28020c1100000d030b20032001411c6a2d00003a00382003200141146a290200370330200341106a200228021022052001410c6a104520032003290310370320200341086a2005200141046a104520032003290308370328200441086a2104200041206b210020012802002106200141206a2101200520064103746a2205280200200341186a2005280204110100450d000b0c010b2002410c6a28020020074b04402003280218200228020820074103746a22002802002000280204200328021c28020c1100000d010b41000c010b41010b200341406b24000b0f00200028020020012002102e41000b5801017f20022000280200200028020822036b4b044020002003200210311032200028020821030b200028020420036a2001200210091a2003200220036a22014b044041d08504411c41808a04100b000b200020013602080bbe0201027f230041106b220224000240024002400240200028020022002002410c6a027f0240024020014180014f04402002410036020c2001418010490d012001418080044f0d0220022001413f71418001723a000e20022001410c7641e001723a000c20022001410676413f71418001723a000d41030c030b200028020822032000280200460d030c040b20022001413f71418001723a000d2002200141067641c001723a000c41020c010b20022001413f71418001723a000f20022001410676413f71418001723a000e20022001410c76413f71418001723a000d2002200141127641077141f001723a000c41040b102e0c020b20002003410110311032200028020821030b200028020420036a20013a0000200341016a2201450d01200020013602080b200241106a240041000f0b41d08504411c41f08904100b000b4a01017f230041206b220224002000280200200241186a200141106a290200370300200241106a200141086a29020037030020022001290200370308200241086a102b200241206a24000b990401067f230041206b220324000240027f41002001200120026a22014b0d001a2000280200220220026a22052002490d012005200120012005491b22014108200141084b1b2201417f73411f7621040240200204402003410136021820032002360214200320002802043602100c010b200341003602180b200341106a2106230041106b220524002003027f0240027f0240200404400240200141004e044020062802080d012005200110342005280204210220052802000c040b0c040b20062802042208450440200541086a20011034200528020c210220052802080c030b20012102410041a4a404280200220420016a22072004490d021a2006280200210641a8a4042802002007490440200141ffff036a220741107640002202417f46200241ffff0371200247720d022002411074220420074180807c716a22022004490d0241a8a4042002360200200121024100200120046a22072004490d031a0b41a4a404200736020041002004450d021a20042006200810090c020b200320013602040c020b2001210241000b2204044020032004360204200341086a200236020041000c020b20032001360204200341086a410136020041010c010b200341086a410036020041010b360200200541106a240020032802004504402003280204210220002001360200200020023602044181808080780c010b200341086a2802000b200341206a24000f0b41f08504412141948704100b000b1b00024020004181808080784704402000450d01000b0f0b1033000b4601017f230041206b22002400200041146a41013602002000411c6a4100360200200041b88704360210200041a8a00436021820004100360208200041086a41c087041019000ba10101027f027f410041a4a404280200220320016a22022003490d001a024041a8a4042802002002490440200141ffff036a22022001490d012002411076220240002203417f46200341ffff0371200347720d012003411074220320024110746a22022003490d0141a8a40420023602004100200120036a22022003490d021a0b41a4a404200236020020030c010b41000b210220002001360204200020023602000b0300010b0e0020002802001a03400c000b000b0c0042b7f8dbfe9ee1aecb430b4a01017f230041106b2205240020022003490440200320022004102a000b200541086a2003200220011039200528020c21012000200528020836020020002001360204200541106a24000b14002000200120022003419ca20441b08a0410530bd806020b7f027e230041406a2203240020002802002202ad210d0240024002400240024002400240024020024190ce004f044041272100200d210e0240034020004104490d01200341196a20006a220241046b200e200e4290ce0080220d4290ce007e7da7220441ffff037141e4006e220641017441eb8c046a2f00003b0000200241026b2004200641e4006c6b41ffff037141017441eb8c046a2f00003b0000200041046b2100200e42ffc1d72f56200d210e0d000b200da7220241e3004d0d0320004102490d090c020b0c080b41272100200241e3004b0d002002410a490d040c020b200041026b2200200341196a6a200da72202200241ffff037141e4006e220241e4006c6b41ffff037141017441eb8c046a2f00003b00000b2002410a490d01200041024f0d000c050b200041026b2200200341196a6a200241017441eb8c046a2f00003b00000c020b2000450d030b200041016b2200200341196a6a200241306a3a00000b200041274b0d01412820006b412720006b22062001280218220541017122071b2102410021042005410471044041a8a0042104200241a8a00441a8a004103b20026a22024b0d010b412b418080c40020071b2107200341196a20006a2108024020012802084504404101210020012802002202200141046a280200220120072004103e0d01200220082006200128020c11000021000c010b024020022001410c6a28020022094904402005410871450d01200128021c210b2001413036021c20012d0020210c41012100200141013a002020012802002205200141046a280200220a20072004103e0d02200341106a2001200920026b4101103f20032802142202418080c400460d022003280210200520082006200a28020c1100000d0220022005200a10400d022001200c3a00202001200b36021c410021000c020b4101210020012802002202200141046a280200220120072004103e0d01200220082006200128020c11000021000c010b41012100200341086a2001200920026b4101103f200328020c2205418080c400460d00200328020820012802002202200141046a280200220120072004103e0d00200220082006200128020c1100000d00200520022001104021000b200341406b240020000f0b41908a04411c41a48f04100b000b41b08a044121419c9b04100b000ba704010a7f230041106b2203240002400240200020016b22024110490d002002200141036a417c7120016b220049200041044b720d00200220006b22044104490d0020012000103c2206200020016a22082004417c716a2004410371103c6a220220064f0440200441027621050240024003402005450d05200320082005200541c001200541c001491b41949304103d200328020c21052003280208210820032003280200200328020422002000417c7141949404103d200328020c210920032802082107024020032802042200450440410021010c010b2003280200220420004102746a210a4100210103402004220641106a2104410021000240034020012001200020066a280200220b417f73410776200b410676724181828408716a22014d0440200041046a22004110470d010c020b0b41908a04411c418c9604100b000b2004200a470d000b0b20022002200141087641ff81fc0771200141ff81fc07716a418180046c4110766a22024b0d012009450d000b200941027421004100210103402001200120072802002204417f734107762004410676724181828408716a22014b0d02200741046a2107200041046b22000d000b20022002200141087641ff81fc0771200141ff81fc07716a418180046c4110766a22024d0d0441908a04411c41bc9604100b000b41908a04411c419c9604100b000b41908a04411c41ac9604100b000b41908a04411c41fc9504100b000b20012002103c21020b200341106a240020020b4601017f200145044041000f0b024003402002200220002c000041bf7f4a6a22024b0d01200041016a2100200141016b22010d000b20020f0b41908a04411c418c9b04100b000b3e00200220034f044020002003360204200020013602002000410c6a200220036b3602002000200120034102746a3602080f0b418c9c0441232004100b000b39000240027f2002418080c40047044041012000200220012802101101000d011a0b20030d0141000b0f0b200020034100200128020c1100000bae0101027f20022104024002400240200320012d0020220320034103461b41ff0171220341016b0e03010001020b200241016a2203044020034101762104200241017621030c020b41908a04411c41b48f04100b000b41002104200221030b200341016a2102200128021c2103200128020421052001280200210102400340200241016b2202450d01200120032005280210110100450d000b418080c40021030b20002003360204200020043602000b3201017f027f0340200020002004460d011a200441016a2104200220012003280210110100450d000b200441016b0b2000490b4b01017f230041106b22052400200120034d0440200541086a4100200120021039200528020c21012000200528020836020020002001360204200541106a24000f0b2001200320041042000b0e0020002001200241dc910410540bea04010b7f230041106b2209240020002802042104200028020021030240024002402001280208220b410147200128021022024101477145044020024101470d02200320046a210c200141146a28020041016a210a410021022003210003402000200c460d03027f024020002c0000220641004e0440200041016a2105200641ff017121070c010b20002d0001413f7121052006411f7121072006415f4d044020074106742005722107200041026a21050c010b20002d0002413f7120054106747221082006417049044020082007410c74722107200041036a21050c010b200041046a210520022106418080c4002007411274418080f0007120002d0003413f71200841067472722207418080c400460d011a0b2002200520006b6a22062002490d0320070b2108200a41016b220a044020052100200621022008418080c400470d010c040b0b2008418080c400460d02024002402002450d00200220044f04404100210020022004460d010c020b41002100200220036a2c00004140480d010b200321000b2002200420001b21042000200320001b21030c020b200128020020032004200128020428020c11000021000c020b41908a04411c41bc9704100b000b200b450440200128020020032004200128020428020c11000021000c010b2001410c6a2802002200200320046a2003103b22024b0440200941086a2001200020026b4100103f41012100200928020c2202418080c400460d0120092802082001280200220520032004200141046a280200220128020c1100000d01200220052001104021000c010b200128020020032004200128020428020c11000021000b200941106a240020000b140020002802002001200028020428020c1101000b5501027f0240027f02400240200228020041016b0e020103000b200241046a0c010b200120022802044103746a22012802044106470d0120012802000b2802002104410121030b20002004360204200020033602000b4901017f230041206b22032400200341186a200241106a290200370300200341106a200241086a2902003703002003200229020037030820002001200341086a102c200341206a24000bda08010b7f23004190016b22032400200341003b0184012003410a3602800120034281808080a00137037820032002360274200341003602702003200236026c200320013602682003200236026420034100360260200028020421062000280200210720002802082108200341fc006a2109027f0340024002400240024020032d008501450440200341d8006a2003280268220c200328026c2003280270200328027410480240024020032802582201450d00200328025c2100034002400240024002400240027f0240024002400240200328027822020440200220096a41016b2d00002104200041084f04402001200141036a417c712202460440200041086b210a410021020c040b200341d0006a200220016b22022000200020024b1b22022001200041b890041041200341c8006a200420032802502003280254104920032802484101470d02200328024c21010c050b200341306a20042001200010492003280234210120032802300c050b41b08a04412141d49904100b000b2002200041086b220a4b0d010b200441818284086c210b0340200241046a22052002490d04200120026a280200200b73220d417f73200d41818284086b71200120056a280200200b732205417f73200541818284086b7172418081828478710d012002200241086a22024b0d072002200a4d0d000b0b200341406b20012000200241e890041038200341386a2004200328024020032802441049410020032802384101470d011a2002200328023c6a220120024f0d0041908a04411c41f89004100b000b41010b4101460440200141016a2200450d022000200328027022006a22022000490d0320032002360270200220032802782200490d05200341286a2003280268200328026c200220006b2002104820032802282202450d05200328022c2100200341206a20032802782009410441849a0410412002200020032802202003280224104a450d05200341186a200328026020032802702200200c104b20032000360260200328021c2102200328021821000c080b200320032802743602700c060b41908a04411c41c89004100b000b41908a04411c41e49904100b000b41908a04411c41f49904100b000b41908a04411c41d89004100b000b200341106a2003280268200328026c20032802702003280274104820032802142100200328021022010d000b0b4100210020032d0085010d00024020032d008401044020032802642101200328026021040c010b2003280264220120032802602204490d0420012004460d010b200341013a008501200341086a200420012003280268104b200328020c2102200328020821000b20000d010b41000c050b20082d0000450d01200741f48b044104200628020c110000450d010c020b41b08a04412141cc9704100b000b2003410a36028c0120082002047f200320002002200241016b41a4940410382003418c016a410120032802002003280204104a0541000b3a0000200720002002200628020c110000450d010b0b41010b20034190016a24000b4c01037f230041106b220524002002200449200320044b72450440200541086a2003200420011039200528020c2107200528020821060b2000200736020420002006360200200541106a24000b5701027f024002402003450440410021030c010b200141ff017121054101210103402005200220046a2d0000460440200421030c030b2003200441016a2204470d000b0b410021010b20002003360204200020013602000b4d01017f2001200346047f027f034041002001450d011a200141016b210120022d0000210320002d00002104200041016a2100200241016a210220032004460d000b200420036b0b0541010b450b1400200020012002200341d0980441b08a0410530b5801027f230041206b22022400200128020421032001280200200241186a2000280200220041106a290200370300200241106a200041086a290200370300200220002902003703082003200241086a102c200241206a24000b0b002000280200200110430b1800200128020041c4a3044105200128020428020c1100000b990301037f230041406a22022400200028020021034101210002402001280200220441c08b04410c200141046a280200220128020c1100000d0002402003280208220004402002200036020c200241346a4102360200410121002002413c6a4101360200200241d08b0436023020024100360228200241073602142002200241106a36023820022002410c6a36021020042001200241286a1046450d010c020b20032802002200200328020428020c11090042c8b5e0cfca86dbd3897f520d002002200036020c200241346a4102360200410121002002413c6a4101360200200241d08b0436023020024100360228200241083602142002200241106a36023820022002410c6a36021020042001200241286a10460d010b200328020c21002002411c6a4103360200200241246a41033602002002413c6a4105360200200241346a4105360200200241988b043602182002410036021020022000410c6a3602382002200041086a3602302002410236022c200220003602282002200241286a36022020042001200241106a104621000b200241406b240020000bc50101017f230041106b220624000240200120024d0440200220044d0d012002200420051042000b230041306b220024002000200236020420002001360200200041146a41023602002000411c6a41023602002000412c6a410536020020004190920436021020004100360208200041053602242000200041206a3602182000200041046a36022820002000360220200041086a20051019000b200641086a2001200220031028200628020c21012000200628020836020020002001360204200641106a24000b980401047f230041106b22022400024002400240024002400240024002400240024002400240024020002d000041016b0e0b0102030405060708090a0b000b410121002001280200220341a2a00441062001280204220528020c22041100000d0b024020012d0018410471450440200341fc8b04410120041100000d0d200341c4a30441052004110000450d010c0d0b200341fa8b04410220041100000d0c2002200536020420022003360200200241013a000f20022002410f6a360208200241c4a304410510470d0c200241f88b04410210470d0c0b200341d18a044101200411000021000c0b0b20012802004195a004410d200128020428020c11000021000c0a0b20012802004187a004410e200128020428020c11000021000c090b200128020041fc9f04410b200128020428020c11000021000c080b200128020041e29f04411a200128020428020c11000021000c070b200128020041d49f04410e200128020428020c11000021000c060b200128020041c49f044110200128020428020c11000021000c050b200128020041b89f04410c200128020428020c11000021000c040b200128020041ad9f04410b200128020428020c11000021000c030b200128020041a69f044107200128020428020c11000021000c020b200128020041979f04410f200128020428020c11000021000c010b200128020041849f044113200128020428020c11000021000b200241106a240020000b14002000200120022003419ca20441b0a20410530b2800200120024d04402000200220016b3602042000200120036a3602000f0b200541212004100b000b7301017f230041306b220424002004200136020420042000360200200441146a41023602002004411c6a41023602002004412c6a41053602002004200336021020044100360208200441053602242004200441206a3602182004200441046a36022820042004360220200441086a20021019000b0b8a240300418080040ba904617474656d707420746f2073756274726163742077697468206f766572666c6f77636f756c64206e6f742070726f7065726c79206465636f64652073746f7261676520656e7472792f55736572732f7061726974792f2e636172676f2f72656769737472792f7372632f6769746875622e636f6d2d316563633632393964623965633832332f696e6b5f73746f726167652d332e342e302f7372632f7472616974732f6d6f642e72730000004800010061000000a20000000a00000073746f7261676520656e7472792077617320656d707479004800010061000000a30000000a0000002f55736572732f7061726974792f2e636172676f2f72656769737472792f7372632f6769746875622e636f6d2d316563633632393964623965633832332f696e6b5f656e762d332e342e302f7372632f656e67696e652f6f6e5f636861696e2f696d706c732e7273e4000100680000009a00000030000000e4000100680000009f0000002e00000000000000617474656d707420746f206164642077697468206f766572666c6f770900000001000000010000000a000000656e636f756e746572656420756e6578706563746564206572726f729c0101001c000000e400010068000000f600000017000000400e010069000000b800000009000000466c69707065723a3a496e6372656d656e7465642f55736572732f7061726974792f436f64652f3466756e2f666c69707065722f6c69622e72730000f40101002600000010000000050041cc84040b95176469737061746368696e6720696e6b2120636f6e7374727563746f72206661696c65643a200000004c020100250000006469737061746368696e6720696e6b21206d657373616765206661696c65643a200000007c02010021000000f401010026000000630000000d0000000900000004000000040000000b0000000c0000000d000000617474656d707420746f206164642077697468206f766572666c6f7700000000617474656d707420746f206d756c7469706c792077697468206f766572666c6f770000000900000000000000010000000e0000002f55736572732f7061726974792f2e7275737475702f746f6f6c636861696e732f6e696768746c792d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f7261775f7665632e727300240301006f0000008a0100001c0000006361706163697479206f766572666c6f77000000a403010011000000240301006f00000006020000050000006120666f726d617474696e6720747261697420696d706c656d656e746174696f6e2072657475726e656420616e206572726f722f55736572732f7061726974792f2e7275737475702f746f6f6c636861696e732f6e696768746c792d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f666d742e72730000030401006b00000064020000200000002f55736572732f7061726974792f2e7275737475702f746f6f6c636861696e732f6e696768746c792d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f616c6c6f632f7372632f7665632f6d6f642e727300800401006f000000300700000d000000800401006f0000009e07000009000000617474656d707420746f206164642077697468206f766572666c6f7700000000617474656d707420746f2073756274726163742077697468206f766572666c6f7729696e646578206f7574206f6620626f756e64733a20746865206c656e20697320206275742074686520696e64657820697320520501002000000072050100120000003a0000002810010000000000940501000100000094050100010000000900000000000000010000000f00000070616e69636b65642061742027272c20cc05010001000000cd050100030000003a2000002810010000000000e005010002000000202020202c0a280a282f55736572732f7061726974792f2e7275737475702f746f6f6c636861696e732f6e696768746c792d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f666d742f6e756d2e727330303031303230333034303530363037303830393130313131323133313431353136313731383139323032313232323332343235323632373238323933303331333233333334333533363337333833393430343134323433343434353436343734383439353035313532353335343535353635373538353936303631363236333634363536363637363836393730373137323733373437353736373737383739383038313832383338343835383638373838383939303931393239333934393539363937393839392f55736572732f7061726974792f2e7275737475702f746f6f6c636861696e732f6e696768746c792d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f666d742f6d6f642e7273000000330701006e0000005d0500000d000000330701006e000000ed050000380000002f55736572732f7061726974792f2e7275737475702f746f6f6c636861696e732f6e696768746c792d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f6d656d6368722e727300c4070100730000004e0000002f000000c4070100730000005a0000001f000000c4070100730000006300000009000000c4070100730000006800000027000000c407010073000000680000003e00000072616e676520737461727420696e64657820206f7574206f662072616e676520666f7220736c696365206f66206c656e6774682088080100120000009a0801002200000072616e676520656e6420696e64657820cc080100100000009a08010022000000736c69636520696e64657820737461727473206174202062757420656e64732061742000ec08010016000000020901000d0000002f55736572732f7061726974792f2e7275737475702f746f6f6c636861696e732f6e696768746c792d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f697465722e72730000002009010071000000c4050000250000002f55736572732f7061726974792f2e7275737475702f746f6f6c636861696e732f6e696768746c792d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f6d6f642e7273a409010070000000f30300002f000000a409010070000000d30800001e000000736f7572636520736c696365206c656e67746820282920646f6573206e6f74206d617463682064657374696e6174696f6e20736c696365206c656e6774682028340a010015000000490a01002b00000051050100010000002f55736572732f7061726974792f2e7275737475702f746f6f6c636861696e732f6e696768746c792d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f636f756e742e72738c0a01007000000047000000150000008c0a01007000000054000000110000008c0a0100700000005a000000090000008c0a01007000000064000000110000008c0a010070000000660000000d0000002f55736572732f7061726974792f2e7275737475702f746f6f6c636861696e732f6e696768746c792d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f697465722e7273004c0b01006f00000091000000110000004c0b01006f0000004c0200003c0000002f55736572732f7061726974792f2e7275737475702f746f6f6c636861696e732f6e696768746c792d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f7472616974732e7273000000dc0b010071000000ca000000130000002f55736572732f7061726974792f2e7275737475702f746f6f6c636861696e732f6e696768746c792d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f7374722f7061747465726e2e72730000600c010072000000a101000047000000600c010072000000b401000020000000600c010072000000b401000011000000600c010072000000b8010000260000002f55736572732f7061726974792f2e7275737475702f746f6f6c636861696e732f6e696768746c792d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f697465722f7472616974732f616363756d2e7273140d0100780000009500000001000000fd0501006e000000cd01000005000000a810010072000000900100004f00000000000000617474656d707420746f2073756274726163742077697468206f766572666c6f770041f09b040bb308617474656d707420746f206164642077697468206f766572666c6f77617373657274696f6e206661696c65643a206d6964203c3d2073656c662e6c656e28290a28100100000000002f0e0100010000002f55736572732f7061726974792f2e636172676f2f72656769737472792f7372632f6769746875622e636f6d2d316563633632393964623965633832332f696e6b5f656e762d332e342e302f7372632f656e67696e652f6f6e5f636861696e2f6275666665722e7273000000400e010069000000580000001c000000400e0100690000005800000009000000400e0100690000005800000031000000400e0100690000006300000009000000400e010069000000810000001a000000400e0100690000008b000000210000002f55736572732f7061726974792f2e636172676f2f72656769737472792f7372632f6769746875622e636f6d2d316563633632393964623965633832332f696e6b5f656e762d332e342e302f7372632f656e67696e652f6f6e5f636861696e2f6578742e727300000c0f0100660000008c0100001400000045636473615265636f766572794661696c65644c6f6767696e6744697361626c6564556e6b6e6f776e4e6f7443616c6c61626c65436f64654e6f74466f756e645f456e646f776d656e74546f6f4c6f775472616e736665724661696c65645f42656c6f7753756273697374656e63655468726573686f6c644b65794e6f74466f756e6443616c6c6565526576657274656443616c6c6565547261707065644465636f646528100100000000007061696420616e20756e70617961626c65206d657373616765636f756c64206e6f74207265616420696e707574756e61626c6520746f206465636f646520696e707574656e636f756e746572656420756e6b6e6f776e2073656c6563746f72756e61626c6520746f206465636f64652073656c6563746f722f55736572732f7061726974792f2e7275737475702f746f6f6c636861696e732f6e696768746c792d616172636836342d6170706c652d64617277696e2f6c69622f727573746c69622f7372632f727573742f6c6962726172792f636f72652f7372632f736c6963652f696e6465782e72730000a810010072000000820100004700000000000000617474656d707420746f2073756274726163742077697468206f766572666c6f772f55736572732f7061726974792f2e636172676f2f72656769737472792f7372632f6769746875622e636f6d2d316563633632393964623965633832332f7061726974792d7363616c652d636f6465632d332e322e312f7372632f636f6465632e727351110100630000007a0000000e0000004572726f72000000000000000100000002000000030000000400000005000000060000000700000008000000090000000c0000000b000000190000001c0000001600000014000000190000008f100100731001005d10010049100100301001"},"contract":{"name":"flipper","version":"0.1.0","authors":["[your_name] <[your_email]>"]},"V3":{"spec":{"constructors":[{"args":[{"label":"init_value","type":{"displayName":["bool"],"type":0}}],"docs":["Constructor that initializes the `bool` value to the given `init_value`."],"label":"new","payable":false,"selector":"0x9bae9d5e"},{"args":[],"docs":["Constructor that initializes the `bool` value to `false`.","","Constructors can delegate to other constructors."],"label":"default","payable":false,"selector":"0xed4b9d1b"}],"docs":[],"events":[{"args":[{"docs":[],"indexed":false,"label":"from","type":{"displayName":["Option"],"type":5}},{"docs":[],"indexed":false,"label":"count","type":{"displayName":["i32"],"type":1}}],"docs":[" Defines an event that is emitted"," every time inc is invoked."],"label":"Incremented"}],"messages":[{"args":[],"docs":[" A message that can be called on instantiated contracts."," This one flips the value of the stored `bool` from `true`"," to `false` and vice versa."],"label":"flip","mutates":true,"payable":false,"returnType":null,"selector":"0x633aa551"},{"args":[],"docs":[" Simply returns the current value of our `bool`."],"label":"get","mutates":false,"payable":false,"returnType":{"displayName":["bool"],"type":0},"selector":"0x2f865bd9"},{"args":[{"label":"a","type":{"displayName":["u32"],"type":2}},{"label":"b","type":{"displayName":["bool"],"type":0}}],"docs":[" multiple arg method returning a tuple."],"label":"method_returning_tuple","mutates":false,"payable":false,"returnType":{"displayName":[],"type":3},"selector":"0xdb48790e"},{"args":[{"label":"a","type":{"displayName":["u32"],"type":2}},{"label":"b","type":{"displayName":["bool"],"type":0}}],"docs":[" multiple arg method returning a struct."],"label":"method_returning_struct","mutates":false,"payable":false,"returnType":{"displayName":["M2"],"type":4},"selector":"0x5cb3e2d0"},{"args":[],"docs":[" get the current count."],"label":"get_count","mutates":false,"payable":false,"returnType":{"displayName":["i32"],"type":1},"selector":"0xbb20003a"},{"args":[],"docs":[" increment current count by 1"],"label":"inc","mutates":true,"payable":false,"returnType":null,"selector":"0x1d32619f"},{"args":[],"docs":[" decrement current count by 1"],"label":"dec","mutates":true,"payable":false,"returnType":null,"selector":"0xb5d7b4f0"},{"args":[{"label":"n","type":{"displayName":["i32"],"type":1}}],"docs":[" increment current count by n"],"label":"inc_by","mutates":true,"payable":false,"returnType":null,"selector":"0xfe5bd8ea"},{"args":[{"label":"n","type":{"displayName":["i32"],"type":1}}],"docs":[" increment current count by n and emit an event"],"label":"inc_by_with_event","mutates":true,"payable":false,"returnType":null,"selector":"0xd54ee71c"}]},"storage":{"struct":{"fields":[{"layout":{"cell":{"key":"0x0000000000000000000000000000000000000000000000000000000000000000","ty":0}},"name":"value"},{"layout":{"cell":{"key":"0x0100000000000000000000000000000000000000000000000000000000000000","ty":1}},"name":"count"}]}},"types":[{"id":0,"type":{"def":{"primitive":"bool"}}},{"id":1,"type":{"def":{"primitive":"i32"}}},{"id":2,"type":{"def":{"primitive":"u32"}}},{"id":3,"type":{"def":{"tuple":[2,0]}}},{"id":4,"type":{"def":{"composite":{"fields":[{"name":"a","type":2,"typeName":"u32"},{"name":"b","type":0,"typeName":"bool"}]}},"path":["flipper","flipper","M2"]}},{"id":5,"type":{"def":{"variant":{"variants":[{"index":0,"name":"None"},{"fields":[{"type":6}],"index":1,"name":"Some"}]}},"params":[{"name":"T","type":6}],"path":["Option"]}},{"id":6,"type":{"def":{"composite":{"fields":[{"type":7,"typeName":"[u8; 32]"}]}},"path":["ink_env","types","AccountId"]}},{"id":7,"type":{"def":{"array":{"len":32,"type":8}}}},{"id":8,"type":{"def":{"primitive":"u8"}}}]}} \ No newline at end of file diff --git a/examples/smart_contract/flipper.wasm b/examples/smart_contract/flipper.wasm new file mode 100644 index 000000000..853e9eb99 Binary files /dev/null and b/examples/smart_contract/flipper.wasm differ diff --git a/examples/smart_contract/metadata.json b/examples/smart_contract/metadata.json new file mode 100644 index 000000000..3c897ad5d --- /dev/null +++ b/examples/smart_contract/metadata.json @@ -0,0 +1,422 @@ +{ + "source": { + "hash": "0x1e3986af05daee058d114887d78d251e7bad3700b7e5aa01741572162d7b3d85", + "language": "ink! 3.4.0", + "compiler": "rustc 1.68.0-nightly" + }, + "contract": { + "name": "flipper", + "version": "0.1.0", + "authors": [ + "[your_name] <[your_email]>" + ] + }, + "V3": { + "spec": { + "constructors": [ + { + "args": [ + { + "label": "init_value", + "type": { + "displayName": [ + "bool" + ], + "type": 0 + } + } + ], + "docs": [ + "Constructor that initializes the `bool` value to the given `init_value`." + ], + "label": "new", + "payable": false, + "selector": "0x9bae9d5e" + }, + { + "args": [], + "docs": [ + "Constructor that initializes the `bool` value to `false`.", + "", + "Constructors can delegate to other constructors." + ], + "label": "default", + "payable": false, + "selector": "0xed4b9d1b" + } + ], + "docs": [], + "events": [ + { + "args": [ + { + "docs": [], + "indexed": false, + "label": "from", + "type": { + "displayName": [ + "Option" + ], + "type": 5 + } + }, + { + "docs": [], + "indexed": false, + "label": "count", + "type": { + "displayName": [ + "i32" + ], + "type": 1 + } + } + ], + "docs": [ + " Defines an event that is emitted", + " every time inc is invoked." + ], + "label": "Incremented" + } + ], + "messages": [ + { + "args": [], + "docs": [ + " A message that can be called on instantiated contracts.", + " This one flips the value of the stored `bool` from `true`", + " to `false` and vice versa." + ], + "label": "flip", + "mutates": true, + "payable": false, + "returnType": null, + "selector": "0x633aa551" + }, + { + "args": [], + "docs": [ + " Simply returns the current value of our `bool`." + ], + "label": "get", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "bool" + ], + "type": 0 + }, + "selector": "0x2f865bd9" + }, + { + "args": [ + { + "label": "a", + "type": { + "displayName": [ + "u32" + ], + "type": 2 + } + }, + { + "label": "b", + "type": { + "displayName": [ + "bool" + ], + "type": 0 + } + } + ], + "docs": [ + " multiple arg method returning a tuple." + ], + "label": "method_returning_tuple", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [], + "type": 3 + }, + "selector": "0xdb48790e" + }, + { + "args": [ + { + "label": "a", + "type": { + "displayName": [ + "u32" + ], + "type": 2 + } + }, + { + "label": "b", + "type": { + "displayName": [ + "bool" + ], + "type": 0 + } + } + ], + "docs": [ + " multiple arg method returning a struct." + ], + "label": "method_returning_struct", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "M2" + ], + "type": 4 + }, + "selector": "0x5cb3e2d0" + }, + { + "args": [], + "docs": [ + " get the current count." + ], + "label": "get_count", + "mutates": false, + "payable": false, + "returnType": { + "displayName": [ + "i32" + ], + "type": 1 + }, + "selector": "0xbb20003a" + }, + { + "args": [], + "docs": [ + " increment current count by 1" + ], + "label": "inc", + "mutates": true, + "payable": false, + "returnType": null, + "selector": "0x1d32619f" + }, + { + "args": [], + "docs": [ + " decrement current count by 1" + ], + "label": "dec", + "mutates": true, + "payable": false, + "returnType": null, + "selector": "0xb5d7b4f0" + }, + { + "args": [ + { + "label": "n", + "type": { + "displayName": [ + "i32" + ], + "type": 1 + } + } + ], + "docs": [ + " increment current count by n" + ], + "label": "inc_by", + "mutates": true, + "payable": false, + "returnType": null, + "selector": "0xfe5bd8ea" + }, + { + "args": [ + { + "label": "n", + "type": { + "displayName": [ + "i32" + ], + "type": 1 + } + } + ], + "docs": [ + " increment current count by n and emit an event" + ], + "label": "inc_by_with_event", + "mutates": true, + "payable": false, + "returnType": null, + "selector": "0xd54ee71c" + } + ] + }, + "storage": { + "struct": { + "fields": [ + { + "layout": { + "cell": { + "key": "0x0000000000000000000000000000000000000000000000000000000000000000", + "ty": 0 + } + }, + "name": "value" + }, + { + "layout": { + "cell": { + "key": "0x0100000000000000000000000000000000000000000000000000000000000000", + "ty": 1 + } + }, + "name": "count" + } + ] + } + }, + "types": [ + { + "id": 0, + "type": { + "def": { + "primitive": "bool" + } + } + }, + { + "id": 1, + "type": { + "def": { + "primitive": "i32" + } + } + }, + { + "id": 2, + "type": { + "def": { + "primitive": "u32" + } + } + }, + { + "id": 3, + "type": { + "def": { + "tuple": [ + 2, + 0 + ] + } + } + }, + { + "id": 4, + "type": { + "def": { + "composite": { + "fields": [ + { + "name": "a", + "type": 2, + "typeName": "u32" + }, + { + "name": "b", + "type": 0, + "typeName": "bool" + } + ] + } + }, + "path": [ + "flipper", + "flipper", + "M2" + ] + } + }, + { + "id": 5, + "type": { + "def": { + "variant": { + "variants": [ + { + "index": 0, + "name": "None" + }, + { + "fields": [ + { + "type": 6 + } + ], + "index": 1, + "name": "Some" + } + ] + } + }, + "params": [ + { + "name": "T", + "type": 6 + } + ], + "path": [ + "Option" + ] + } + }, + { + "id": 6, + "type": { + "def": { + "composite": { + "fields": [ + { + "type": 7, + "typeName": "[u8; 32]" + } + ] + } + }, + "path": [ + "ink_env", + "types", + "AccountId" + ] + } + }, + { + "id": 7, + "type": { + "def": { + "array": { + "len": 32, + "type": 8 + } + } + } + }, + { + "id": 8, + "type": { + "def": { + "primitive": "u8" + } + } + } + ] + } +} diff --git a/examples/smart_contract/zombienet.toml b/examples/smart_contract/zombienet.toml new file mode 100644 index 000000000..412088413 --- /dev/null +++ b/examples/smart_contract/zombienet.toml @@ -0,0 +1,24 @@ +[relaychain] +default_image = "docker.io/paritypr/polkadot-debug:master" +default_command = "polkadot" +default_args = ["-lparachain=debug"] +chain = "rococo-local" + +[[relaychain.nodes]] +name = "alice" +validator = true + +[[relaychain.nodes]] +name = "bob" +validator = true + +[[parachains]] +id = 1000 +cumulus_based = true +chain = "contracts-rococo-local" + +[parachains.collator] +name = "collator01" +image = "docker.io/parity/polkadot-parachain:latest" +command = "polkadot-parachain" +args = ["-lparachain=debug"] diff --git a/fluent/Contract.ts b/fluent/Contract.ts new file mode 100644 index 000000000..a581a32cd --- /dev/null +++ b/fluent/Contract.ts @@ -0,0 +1,74 @@ +import * as Z from "../deps/zones.ts" +import { contracts, events } from "../effects/mod.ts" +import { ContractMetadata, MultiAddress, Signer } from "../frame_metadata/mod.ts" +import * as rpc from "../rpc/mod.ts" + +export interface ContractCallProps { + sender: MultiAddress + messageLabel: string + args: Args +} +export interface ContractCallTxProps + extends ContractCallProps +{ + value?: bigint + sign: Signer +} + +// TODO: codegen each contract message as a method +// TODO: model ctor inputs as effects +export class Contract> { + constructor( + readonly client: Client, + readonly contractMetadata: ContractMetadata, + readonly contractAddress: Uint8Array, + ) {} + + #basePayload< + Sender extends Z.$, + MessageLabel extends Z.$, + Args extends Z.$, + >( + sender: Sender, + messageLabel: MessageLabel, + args: Args, + ) { + return { + sender, + contractAddress: this.contractAddress, + contractMetadata: this.contractMetadata, + message: this.#getMessageByLabel(messageLabel)!, + args, + } + } + + call>(props: Props) { + return contracts.call(this.client)( + this.#basePayload(props.sender, props.messageLabel, props.args), + ) + } + + callTx>(props: Props) { + const tx = contracts.callTx(this.client)({ + ...this.#basePayload(props.sender, props.messageLabel, props.args), + value: props.value, + }).signed(props.sign) + const finalizedIn = tx.watch(({ end }) => (status) => { + if (typeof status !== "string" && (status.inBlock ?? status.finalized)) { + return end(status.inBlock ?? status.finalized) + } else if (rpc.known.TransactionStatus.isTerminal(status)) { + return end(new Error()) + } + return + }) + const events_ = events(tx, finalizedIn) + const contractEvents = contracts.events(this.contractMetadata, events_) + return Z.ls(finalizedIn, events_, contractEvents) + } + + #getMessageByLabel