diff --git a/examples/raffle/MockVRFBeaconClient.ts b/examples/raffle/MockVRFBeaconClient.ts new file mode 100644 index 000000000..e027d6176 --- /dev/null +++ b/examples/raffle/MockVRFBeaconClient.ts @@ -0,0 +1,448 @@ +/* eslint-disable */ +/** + * This file was automatically generated by @algorandfoundation/algokit-client-generator. + * DO NOT MODIFY IT BY HAND. + * requires: @algorandfoundation/algokit-utils: ^2 + */ +import * as algokit from '@algorandfoundation/algokit-utils' +import type { + AppCallTransactionResult, + AppCallTransactionResultOfType, + CoreAppCallArgs, + RawAppCallArgs, + AppState, + TealTemplateParams, + ABIAppCallArg, +} from '@algorandfoundation/algokit-utils/types/app' +import type { + AppClientCallCoreParams, + AppClientCompilationParams, + AppClientDeployCoreParams, + AppDetails, + ApplicationClient, +} from '@algorandfoundation/algokit-utils/types/app-client' +import type { AppSpec } from '@algorandfoundation/algokit-utils/types/app-spec' +import type { SendTransactionResult, TransactionToSign, SendTransactionFrom } from '@algorandfoundation/algokit-utils/types/transaction' +import type { TransactionWithSigner } from 'algosdk' +import { Algodv2, OnApplicationComplete, Transaction, AtomicTransactionComposer } from 'algosdk' +export const APP_SPEC: AppSpec = { + "hints": { + "must_get(uint64,byte[])byte[]": { + "call_config": { + "no_op": "CALL" + } + }, + "createApplication()void": { + "call_config": { + "no_op": "CREATE" + } + } + }, + "bare_call_config": { + "no_op": "NEVER", + "opt_in": "NEVER", + "close_out": "NEVER", + "update_application": "NEVER", + "delete_application": "NEVER" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": {}, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDkKCi8vIFRoaXMgVEVBTCB3YXMgZ2VuZXJhdGVkIGJ5IFRFQUxTY3JpcHQgdjAuNjUuMAovLyBodHRwczovL2dpdGh1Yi5jb20vYWxnb3JhbmRmb3VuZGF0aW9uL1RFQUxTY3JpcHQKCi8vIFRoaXMgY29udHJhY3QgaXMgY29tcGxpYW50IHdpdGggYW5kL29yIGltcGxlbWVudHMgdGhlIGZvbGxvd2luZyBBUkNzOiBbIEFSQzQgXQoKLy8gVGhlIGZvbGxvd2luZyB0ZW4gbGluZXMgb2YgVEVBTCBoYW5kbGUgaW5pdGlhbCBwcm9ncmFtIGZsb3cKLy8gVGhpcyBwYXR0ZXJuIGlzIHVzZWQgdG8gbWFrZSBpdCBlYXN5IGZvciBhbnlvbmUgdG8gcGFyc2UgdGhlIHN0YXJ0IG9mIHRoZSBwcm9ncmFtIGFuZCBkZXRlcm1pbmUgaWYgYSBzcGVjaWZpYyBhY3Rpb24gaXMgYWxsb3dlZAovLyBIZXJlLCBhY3Rpb24gcmVmZXJzIHRvIHRoZSBPbkNvbXBsZXRlIGluIGNvbWJpbmF0aW9uIHdpdGggd2hldGhlciB0aGUgYXBwIGlzIGJlaW5nIGNyZWF0ZWQgb3IgY2FsbGVkCi8vIEV2ZXJ5IHBvc3NpYmxlIGFjdGlvbiBmb3IgdGhpcyBjb250cmFjdCBpcyByZXByZXNlbnRlZCBpbiB0aGUgc3dpdGNoIHN0YXRlbWVudAovLyBJZiB0aGUgYWN0aW9uIGlzIG5vdCBpbXBsbWVudGVkIGluIHRoZSBjb250cmFjdCwgaXRzIHJlcHNlY3RpdmUgYnJhbmNoIHdpbGwgYmUgIk5PVF9JTVBMTUVOVEVEIiB3aGljaCBqdXN0IGNvbnRhaW5zICJlcnIiCnR4biBBcHBsaWNhdGlvbklECmludCAwCj4KaW50IDYKKgp0eG4gT25Db21wbGV0aW9uCisKc3dpdGNoIGNyZWF0ZV9Ob09wIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgTk9UX0lNUExFTUVOVEVEIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgY2FsbF9Ob09wCgpOT1RfSU1QTEVNRU5URUQ6CgllcnIKCi8vIG11c3RfZ2V0KGJ5dGVzLHVpbnQ2NClieXRlW10KYWJpX3JvdXRlX211c3RfZ2V0OgoJLy8gZGF0YTogYnl0ZVtdCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglleHRyYWN0IDIgMAoKCS8vIF9yb3VuZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBtdXN0X2dldChieXRlcyx1aW50NjQpYnl0ZVtdCgljYWxsc3ViIG11c3RfZ2V0CglpbnQgMQoJcmV0dXJuCgptdXN0X2dldDoKCXByb3RvIDIgMAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoyMDAKCS8vIHJldHVybiBzaGEyNTYoZGF0YSArIGl0b2IoZ2xvYmFscy5yb3VuZCkpIGFzIGJ5dGVzOwoJZnJhbWVfZGlnIC0yIC8vIGRhdGE6IGJ5dGVzCglnbG9iYWwgUm91bmQKCWl0b2IKCWNvbmNhdAoJc2hhMjU2CglkdXAKCWxlbgoJaXRvYgoJZXh0cmFjdCA2IDIKCXN3YXAKCWNvbmNhdAoJYnl0ZSAweDE1MWY3Yzc1Cglzd2FwCgljb25jYXQKCWxvZwoJcmV0c3ViCgphYmlfcm91dGVfY3JlYXRlQXBwbGljYXRpb246CglpbnQgMQoJcmV0dXJuCgpjcmVhdGVfTm9PcDoKCW1ldGhvZCAiY3JlYXRlQXBwbGljYXRpb24oKXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCBhYmlfcm91dGVfY3JlYXRlQXBwbGljYXRpb24KCWVycgoKY2FsbF9Ob09wOgoJbWV0aG9kICJtdXN0X2dldCh1aW50NjQsYnl0ZVtdKWJ5dGVbXSIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV9tdXN0X2dldAoJZXJy", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDk=" + }, + "contract": { + "name": "MockVRFBeacon", + "desc": "", + "methods": [ + { + "name": "must_get", + "args": [ + { + "name": "_round", + "type": "uint64", + "desc": "" + }, + { + "name": "data", + "type": "byte[]", + "desc": "" + } + ], + "desc": "", + "returns": { + "type": "byte[]", + "desc": "" + } + }, + { + "name": "createApplication", + "desc": "", + "returns": { + "type": "void", + "desc": "" + }, + "args": [] + } + ] + } +} + +/** + * Defines an onCompletionAction of 'no_op' + */ +export type OnCompleteNoOp = { onCompleteAction?: 'no_op' | OnApplicationComplete.NoOpOC } +/** + * Defines an onCompletionAction of 'opt_in' + */ +export type OnCompleteOptIn = { onCompleteAction: 'opt_in' | OnApplicationComplete.OptInOC } +/** + * Defines an onCompletionAction of 'close_out' + */ +export type OnCompleteCloseOut = { onCompleteAction: 'close_out' | OnApplicationComplete.CloseOutOC } +/** + * Defines an onCompletionAction of 'delete_application' + */ +export type OnCompleteDelApp = { onCompleteAction: 'delete_application' | OnApplicationComplete.DeleteApplicationOC } +/** + * Defines an onCompletionAction of 'update_application' + */ +export type OnCompleteUpdApp = { onCompleteAction: 'update_application' | OnApplicationComplete.UpdateApplicationOC } +/** + * A state record containing a single unsigned integer + */ +export type IntegerState = { + /** + * Gets the state value as a BigInt + */ + asBigInt(): bigint + /** + * Gets the state value as a number. + */ + asNumber(): number +} +/** + * A state record containing binary data + */ +export type BinaryState = { + /** + * Gets the state value as a Uint8Array + */ + asByteArray(): Uint8Array + /** + * Gets the state value as a string + */ + asString(): string +} + +/** + * Defines the types of available calls and state of the MockVrfBeacon smart contract. + */ +export type MockVrfBeacon = { + /** + * Maps method signatures / names to their argument and return types. + */ + methods: + & Record<'must_get(uint64,byte[])byte[]' | 'must_get', { + argsObj: { + _round: bigint | number + data: Uint8Array + } + argsTuple: [_round: bigint | number, data: Uint8Array] + returns: Uint8Array + }> + & Record<'createApplication()void' | 'createApplication', { + argsObj: { + } + argsTuple: [] + returns: void + }> +} +/** + * Defines the possible abi call signatures + */ +export type MockVrfBeaconSig = keyof MockVrfBeacon['methods'] +/** + * Defines an object containing all relevant parameters for a single call to the contract. Where TSignature is undefined, a bare call is made + */ +export type TypedCallParams = { + method: TSignature + methodArgs: TSignature extends undefined ? undefined : Array +} & AppClientCallCoreParams & CoreAppCallArgs +/** + * Defines the arguments required for a bare call + */ +export type BareCallArgs = Omit +/** + * Maps a method signature from the MockVrfBeacon smart contract to the method's arguments in either tuple of struct form + */ +export type MethodArgs = MockVrfBeacon['methods'][TSignature]['argsObj' | 'argsTuple'] +/** + * Maps a method signature from the MockVrfBeacon smart contract to the method's return type + */ +export type MethodReturn = MockVrfBeacon['methods'][TSignature]['returns'] + +/** + * A factory for available 'create' calls + */ +export type MockVrfBeaconCreateCalls = (typeof MockVrfBeaconCallFactory)['create'] +/** + * Defines supported create methods for this smart contract + */ +export type MockVrfBeaconCreateCallParams = + | (TypedCallParams<'createApplication()void'> & (OnCompleteNoOp)) +/** + * Defines arguments required for the deploy method. + */ +export type MockVrfBeaconDeployArgs = { + deployTimeParams?: TealTemplateParams + /** + * A delegate which takes a create call factory and returns the create call params for this smart contract + */ + createCall?: (callFactory: MockVrfBeaconCreateCalls) => MockVrfBeaconCreateCallParams +} + + +/** + * Exposes methods for constructing all available smart contract calls + */ +export abstract class MockVrfBeaconCallFactory { + /** + * Gets available create call factories + */ + static get create() { + return { + /** + * Constructs a create call for the MockVRFBeacon smart contract using the createApplication()void ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + createApplication(args: MethodArgs<'createApplication()void'>, params: AppClientCallCoreParams & CoreAppCallArgs & AppClientCompilationParams & (OnCompleteNoOp) = {}) { + return { + method: 'createApplication()void' as const, + methodArgs: Array.isArray(args) ? args : [], + ...params, + } + }, + } + } + + /** + * Constructs a no op call for the must_get(uint64,byte[])byte[] ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static mustGet(args: MethodArgs<'must_get(uint64,byte[])byte[]'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'must_get(uint64,byte[])byte[]' as const, + methodArgs: Array.isArray(args) ? args : [args._round, args.data], + ...params, + } + } +} + +/** + * A client to make calls to the MockVRFBeacon smart contract + */ +export class MockVrfBeaconClient { + /** + * The underlying `ApplicationClient` for when you want to have more flexibility + */ + public readonly appClient: ApplicationClient + + private readonly sender: SendTransactionFrom | undefined + + /** + * Creates a new instance of `MockVrfBeaconClient` + * + * @param appDetails appDetails The details to identify the app to deploy + * @param algod An algod client instance + */ + constructor(appDetails: AppDetails, private algod: Algodv2) { + this.sender = appDetails.sender + this.appClient = algokit.getAppClient({ + ...appDetails, + app: APP_SPEC + }, algod) + } + + /** + * Checks for decode errors on the AppCallTransactionResult and maps the return value to the specified generic type + * + * @param result The AppCallTransactionResult to be mapped + * @param returnValueFormatter An optional delegate to format the return value if required + * @returns The smart contract response with an updated return value + */ + protected mapReturnValue(result: AppCallTransactionResult, returnValueFormatter?: (value: any) => TReturn): AppCallTransactionResultOfType { + if(result.return?.decodeError) { + throw result.return.decodeError + } + const returnValue = result.return?.returnValue !== undefined && returnValueFormatter !== undefined + ? returnValueFormatter(result.return.returnValue) + : result.return?.returnValue as TReturn | undefined + return { ...result, return: returnValue } + } + + /** + * Calls the ABI method with the matching signature using an onCompletion code of NO_OP + * + * @param typedCallParams An object containing the method signature, args, and any other relevant parameters + * @param returnValueFormatter An optional delegate which when provided will be used to map non-undefined return values to the target type + * @returns The result of the smart contract call + */ + public async call(typedCallParams: TypedCallParams, returnValueFormatter?: (value: any) => MethodReturn) { + return this.mapReturnValue>(await this.appClient.call(typedCallParams), returnValueFormatter) + } + + /** + * Idempotently deploys the MockVRFBeacon smart contract. + * + * @param params The arguments for the contract calls and any additional parameters for the call + * @returns The deployment result + */ + public deploy(params: MockVrfBeaconDeployArgs & AppClientDeployCoreParams = {}): ReturnType { + const createArgs = params.createCall?.(MockVrfBeaconCallFactory.create) + return this.appClient.deploy({ + ...params, + createArgs, + createOnCompleteAction: createArgs?.onCompleteAction, + }) + } + + /** + * Gets available create methods + */ + public get create() { + const $this = this + return { + /** + * Creates a new instance of the MockVRFBeacon smart contract using the createApplication()void ABI method. + * + * @param args The arguments for the smart contract call + * @param params Any additional parameters for the call + * @returns The create result + */ + async createApplication(args: MethodArgs<'createApplication()void'>, params: AppClientCallCoreParams & AppClientCompilationParams & (OnCompleteNoOp) = {}): Promise>> { + return $this.mapReturnValue(await $this.appClient.create(MockVrfBeaconCallFactory.create.createApplication(args, params))) + }, + } + } + + /** + * Makes a clear_state call to an existing instance of the MockVRFBeacon smart contract. + * + * @param args The arguments for the bare call + * @returns The clear_state result + */ + public clearState(args: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.appClient.clearState(args) + } + + /** + * Calls the must_get(uint64,byte[])byte[] ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public mustGet(args: MethodArgs<'must_get(uint64,byte[])byte[]'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(MockVrfBeaconCallFactory.mustGet(args, params)) + } + + public compose(): MockVrfBeaconComposer { + const client = this + const atc = new AtomicTransactionComposer() + let promiseChain:Promise = Promise.resolve() + const resultMappers: Array any)> = [] + return { + mustGet(args: MethodArgs<'must_get(uint64,byte[])byte[]'>, params?: AppClientCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.mustGet(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + clearState(args?: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.clearState({...args, sendParams: {...args?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + addTransaction(txn: TransactionWithSigner | TransactionToSign | Transaction | Promise, defaultSender?: SendTransactionFrom) { + promiseChain = promiseChain.then(async () => atc.addTransaction(await algokit.getTransactionWithSigner(txn, defaultSender ?? client.sender))) + return this + }, + async atc() { + await promiseChain + return atc + }, + async execute() { + await promiseChain + const result = await algokit.sendAtomicTransactionComposer({ atc, sendParams: {} }, client.algod) + return { + ...result, + returns: result.returns?.map((val, i) => resultMappers[i] !== undefined ? resultMappers[i]!(val.returnValue) : val.returnValue) + } + } + } as unknown as MockVrfBeaconComposer + } +} +export type MockVrfBeaconComposer = { + /** + * Calls the must_get(uint64,byte[])byte[] ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + mustGet(args: MethodArgs<'must_get(uint64,byte[])byte[]'>, params?: AppClientCallCoreParams & CoreAppCallArgs): MockVrfBeaconComposer<[...TReturns, MethodReturn<'must_get(uint64,byte[])byte[]'>]> + + /** + * Makes a clear_state call to an existing instance of the MockVRFBeacon smart contract. + * + * @param args The arguments for the bare call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + clearState(args?: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs): MockVrfBeaconComposer<[...TReturns, undefined]> + + /** + * Adds a transaction to the composer + * + * @param txn One of: A TransactionWithSigner object (returned as is), a TransactionToSign object (signer is obtained from the signer property), a Transaction object (signer is extracted from the defaultSender parameter), an async SendTransactionResult returned by one of algokit utils helpers (signer is obtained from the defaultSender parameter) + * @param defaultSender The default sender to be used to obtain a signer where the object provided to the transaction parameter does not include a signer. + */ + addTransaction(txn: TransactionWithSigner | TransactionToSign | Transaction | Promise, defaultSender?: SendTransactionFrom): MockVrfBeaconComposer + /** + * Returns the underlying AtomicTransactionComposer instance + */ + atc(): Promise + /** + * Executes the transaction group and returns an array of results + */ + execute(): Promise> +} +export type MockVrfBeaconComposerResults = { + returns: TReturns + groupId: string + txIds: string[] + transactions: Transaction[] +} diff --git a/examples/raffle/NFTRaffleClient.ts b/examples/raffle/NFTRaffleClient.ts new file mode 100644 index 000000000..01fe94155 --- /dev/null +++ b/examples/raffle/NFTRaffleClient.ts @@ -0,0 +1,962 @@ +/* eslint-disable */ +/** + * This file was automatically generated by @algorandfoundation/algokit-client-generator. + * DO NOT MODIFY IT BY HAND. + * requires: @algorandfoundation/algokit-utils: ^2 + */ +import * as algokit from '@algorandfoundation/algokit-utils' +import type { + AppCallTransactionResult, + AppCallTransactionResultOfType, + CoreAppCallArgs, + RawAppCallArgs, + AppState, + TealTemplateParams, + ABIAppCallArg, +} from '@algorandfoundation/algokit-utils/types/app' +import type { + AppClientCallCoreParams, + AppClientCompilationParams, + AppClientDeployCoreParams, + AppDetails, + ApplicationClient, +} from '@algorandfoundation/algokit-utils/types/app-client' +import type { AppSpec } from '@algorandfoundation/algokit-utils/types/app-spec' +import type { SendTransactionResult, TransactionToSign, SendTransactionFrom } from '@algorandfoundation/algokit-utils/types/transaction' +import type { TransactionWithSigner } from 'algosdk' +import { Algodv2, OnApplicationComplete, Transaction, AtomicTransactionComposer } from 'algosdk' +export const APP_SPEC: AppSpec = { + "hints": { + "createApplication(uint64,uint64)void": { + "call_config": { + "no_op": "CREATE" + } + }, + "setAsset(asset)void": { + "call_config": { + "no_op": "CALL" + } + }, + "startRaffle(axfer,uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "buyTickets(pay,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "draw(application)bool": { + "call_config": { + "no_op": "CALL" + } + }, + "claim()void": { + "call_config": { + "no_op": "CALL" + } + }, + "getRefund()void": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "NEVER", + "opt_in": "NEVER", + "close_out": "NEVER", + "update_application": "NEVER", + "delete_application": "NEVER" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": { + "randomnessOracle": { + "type": "uint64", + "key": "randomnessOracle" + }, + "ticketPrice": { + "type": "uint64", + "key": "ticketPrice" + }, + "asset": { + "type": "uint64", + "key": "asset" + }, + "endRound": { + "type": "uint64", + "key": "endRound" + }, + "drawRound": { + "type": "uint64", + "key": "drawRound" + }, + "totalTickets": { + "type": "uint64", + "key": "totalTickets" + }, + "winningTicket": { + "type": "uint64", + "key": "winningTicket" + }, + "randomBytes": { + "type": "bytes", + "key": "randomBytes" + } + }, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 1, + "num_uints": 7 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDkKCi8vIFRoaXMgVEVBTCB3YXMgZ2VuZXJhdGVkIGJ5IFRFQUxTY3JpcHQgdjAuNjUuMAovLyBodHRwczovL2dpdGh1Yi5jb20vYWxnb3JhbmRmb3VuZGF0aW9uL1RFQUxTY3JpcHQKCi8vIFRoaXMgY29udHJhY3QgaXMgY29tcGxpYW50IHdpdGggYW5kL29yIGltcGxlbWVudHMgdGhlIGZvbGxvd2luZyBBUkNzOiBbIEFSQzQgXQoKLy8gVGhlIGZvbGxvd2luZyB0ZW4gbGluZXMgb2YgVEVBTCBoYW5kbGUgaW5pdGlhbCBwcm9ncmFtIGZsb3cKLy8gVGhpcyBwYXR0ZXJuIGlzIHVzZWQgdG8gbWFrZSBpdCBlYXN5IGZvciBhbnlvbmUgdG8gcGFyc2UgdGhlIHN0YXJ0IG9mIHRoZSBwcm9ncmFtIGFuZCBkZXRlcm1pbmUgaWYgYSBzcGVjaWZpYyBhY3Rpb24gaXMgYWxsb3dlZAovLyBIZXJlLCBhY3Rpb24gcmVmZXJzIHRvIHRoZSBPbkNvbXBsZXRlIGluIGNvbWJpbmF0aW9uIHdpdGggd2hldGhlciB0aGUgYXBwIGlzIGJlaW5nIGNyZWF0ZWQgb3IgY2FsbGVkCi8vIEV2ZXJ5IHBvc3NpYmxlIGFjdGlvbiBmb3IgdGhpcyBjb250cmFjdCBpcyByZXByZXNlbnRlZCBpbiB0aGUgc3dpdGNoIHN0YXRlbWVudAovLyBJZiB0aGUgYWN0aW9uIGlzIG5vdCBpbXBsbWVudGVkIGluIHRoZSBjb250cmFjdCwgaXRzIHJlcHNlY3RpdmUgYnJhbmNoIHdpbGwgYmUgIk5PVF9JTVBMTUVOVEVEIiB3aGljaCBqdXN0IGNvbnRhaW5zICJlcnIiCnR4biBBcHBsaWNhdGlvbklECmludCAwCj4KaW50IDYKKgp0eG4gT25Db21wbGV0aW9uCisKc3dpdGNoIGNyZWF0ZV9Ob09wIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgTk9UX0lNUExFTUVOVEVEIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgY2FsbF9Ob09wCgpOT1RfSU1QTEVNRU5URUQ6CgllcnIKCi8vIGNyZWF0ZUFwcGxpY2F0aW9uKHVpbnQ2NCx1aW50NjQpdm9pZAovLwovLyBDcmVhdGUgdGhlIHJhZmZsZQovLwovLyBAcGFyYW0gdGlja2V0UHJpY2UgVGhlIHByaWNlIG9mIGEgc2luZ2xlIHRpY2tldCAodUFMR08pCi8vIEBwYXJhbSByYW5kb21uZXNzT3JhY2xlIFRoZSBhcHAgSUQgb2YgdGhlIHJhbmRvbW5lc3Mgb3JhY2xlCmFiaV9yb3V0ZV9jcmVhdGVBcHBsaWNhdGlvbjoKCS8vIHJhbmRvbW5lc3NPcmFjbGU6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIHRpY2tldFByaWNlOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGNyZWF0ZUFwcGxpY2F0aW9uKHVpbnQ2NCx1aW50NjQpdm9pZAoJY2FsbHN1YiBjcmVhdGVBcHBsaWNhdGlvbgoJaW50IDEKCXJldHVybgoKY3JlYXRlQXBwbGljYXRpb246Cglwcm90byAyIDAKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6NDMKCS8vIHRoaXMucmFuZG9tbmVzc09yYWNsZS52YWx1ZSA9IHJhbmRvbW5lc3NPcmFjbGUKCWJ5dGUgMHg3MjYxNmU2NDZmNmQ2ZTY1NzM3MzRmNzI2MTYzNmM2NSAvLyAicmFuZG9tbmVzc09yYWNsZSIKCWZyYW1lX2RpZyAtMiAvLyByYW5kb21uZXNzT3JhY2xlOiB1aW50NjQKCWFwcF9nbG9iYWxfcHV0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjQ0CgkvLyB0aGlzLnRpY2tldFByaWNlLnZhbHVlID0gdGlja2V0UHJpY2UKCWJ5dGUgMHg3NDY5NjM2YjY1NzQ1MDcyNjk2MzY1IC8vICJ0aWNrZXRQcmljZSIKCWZyYW1lX2RpZyAtMSAvLyB0aWNrZXRQcmljZTogdWludDY0CglhcHBfZ2xvYmFsX3B1dAoJcmV0c3ViCgovLyBzZXRBc3NldChhc3NldCl2b2lkCi8vCi8vIFNldCB0aGUgYXNzZXQgdG8gYmUgcmFmZmxlZAovLwovLyBAcGFyYW0gYXNzZXQgVGhlIGFzc2V0IHRvIGJlIHJhZmZsZWQKYWJpX3JvdXRlX3NldEFzc2V0OgoJLy8gYXNzZXQ6IGFzc2V0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgl0eG5hcyBBc3NldHMKCgkvLyBleGVjdXRlIHNldEFzc2V0KGFzc2V0KXZvaWQKCWNhbGxzdWIgc2V0QXNzZXQKCWludCAxCglyZXR1cm4KCnNldEFzc2V0OgoJcHJvdG8gMSAwCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjU0CgkvLyBhc3NlcnQoIXRoaXMuYXNzZXQuZXhpc3RzKQoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJYnl0ZSAweDYxNzM3MzY1NzQgLy8gImFzc2V0IgoJYXBwX2dsb2JhbF9nZXRfZXgKCXN3YXAKCXBvcAoJIQoJYXNzZXJ0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjU2CgkvLyBzZW5kQXNzZXRUcmFuc2Zlcih7CgkvLyAgICAgICBhc3NldFJlY2VpdmVyOiB0aGlzLmFwcC5hZGRyZXNzLAoJLy8gICAgICAgeGZlckFzc2V0OiBhc3NldCwKCS8vICAgICAgIGFzc2V0QW1vdW50OiAwLAoJLy8gICAgICAgZmVlOiAwLAoJLy8gICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXhmZXIKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6NTcKCS8vIGFzc2V0UmVjZWl2ZXI6IHRoaXMuYXBwLmFkZHJlc3MKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCglpdHhuX2ZpZWxkIEFzc2V0UmVjZWl2ZXIKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6NTgKCS8vIHhmZXJBc3NldDogYXNzZXQKCWZyYW1lX2RpZyAtMSAvLyBhc3NldDogYXNzZXQKCWl0eG5fZmllbGQgWGZlckFzc2V0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjU5CgkvLyBhc3NldEFtb3VudDogMAoJaW50IDAKCWl0eG5fZmllbGQgQXNzZXRBbW91bnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6NjAKCS8vIGZlZTogMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo2MwoJLy8gdGhpcy5hc3NldC52YWx1ZSA9IGFzc2V0CglieXRlIDB4NjE3MzczNjU3NCAvLyAiYXNzZXQiCglmcmFtZV9kaWcgLTEgLy8gYXNzZXQ6IGFzc2V0CglhcHBfZ2xvYmFsX3B1dAoJcmV0c3ViCgovLyBzdGFydFJhZmZsZSh1aW50NjQsdWludDY0LGF4ZmVyKXZvaWQKLy8KLy8gU3RhcnQgdGhlIHJhZmZsZQovLwovLyBAcGFyYW0gZW5kIFRoZSByb3VuZCBudW1iZXIgd2hlbiB0aGUgcmFmZmxlIGVuZHMKLy8gQHBhcmFtIGRyYXcgVGhlIHJvdW5kIG51bWJlciB3aGVuIHRoZSByYWZmbGUgaXMgZHJhd24KYWJpX3JvdXRlX3N0YXJ0UmFmZmxlOgoJLy8gZHJhdzogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglidG9pCgoJLy8gZW5kOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBheGZlcjogYXhmZXIKCXR4biBHcm91cEluZGV4CglpbnQgMQoJLQoJZHVwCglndHhucyBUeXBlRW51bQoJaW50IGF4ZmVyCgk9PQoJYXNzZXJ0CgoJLy8gZXhlY3V0ZSBzdGFydFJhZmZsZSh1aW50NjQsdWludDY0LGF4ZmVyKXZvaWQKCWNhbGxzdWIgc3RhcnRSYWZmbGUKCWludCAxCglyZXR1cm4KCnN0YXJ0UmFmZmxlOgoJcHJvdG8gMyAwCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjc0CgkvLyB2ZXJpZnlUeG4oYXhmZXIsIHsKCS8vICAgICAgIGFzc2V0QW1vdW50OiB7IGdyZWF0ZXJUaGFuOiAwIH0sCgkvLyAgICAgICBhc3NldFJlY2VpdmVyOiB0aGlzLmFwcC5hZGRyZXNzLAoJLy8gICAgICAgeGZlckFzc2V0OiB0aGlzLmFzc2V0LnZhbHVlLAoJLy8gICAgIH0pCgkvLyB2ZXJpZnkgYXNzZXRBbW91bnQKCWZyYW1lX2RpZyAtMSAvLyBheGZlcjogYXhmZXIKCWd0eG5zIEFzc2V0QW1vdW50CglpbnQgMAoJPgoJYXNzZXJ0CgoJLy8gdmVyaWZ5IGFzc2V0UmVjZWl2ZXIKCWZyYW1lX2RpZyAtMSAvLyBheGZlcjogYXhmZXIKCWd0eG5zIEFzc2V0UmVjZWl2ZXIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCgk9PQoJYXNzZXJ0CgoJLy8gdmVyaWZ5IHhmZXJBc3NldAoJZnJhbWVfZGlnIC0xIC8vIGF4ZmVyOiBheGZlcgoJZ3R4bnMgWGZlckFzc2V0CglieXRlIDB4NjE3MzczNjU3NCAvLyAiYXNzZXQiCglhcHBfZ2xvYmFsX2dldAoJPT0KCWFzc2VydAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo4MAoJLy8gYXNzZXJ0KGRyYXcgPiBlbmQpCglmcmFtZV9kaWcgLTMgLy8gZHJhdzogdWludDY0CglmcmFtZV9kaWcgLTIgLy8gZW5kOiB1aW50NjQKCT4KCWFzc2VydAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo4MQoJLy8gdGhpcy5lbmRSb3VuZC52YWx1ZSA9IGVuZAoJYnl0ZSAweDY1NmU2NDUyNmY3NTZlNjQgLy8gImVuZFJvdW5kIgoJZnJhbWVfZGlnIC0yIC8vIGVuZDogdWludDY0CglhcHBfZ2xvYmFsX3B1dAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo4MgoJLy8gdGhpcy5kcmF3Um91bmQudmFsdWUgPSBkcmF3CglieXRlIDB4NjQ3MjYxNzc1MjZmNzU2ZTY0IC8vICJkcmF3Um91bmQiCglmcmFtZV9kaWcgLTMgLy8gZHJhdzogdWludDY0CglhcHBfZ2xvYmFsX3B1dAoJcmV0c3ViCgovLyBidXlUaWNrZXRzKHVpbnQ2NCxwYXkpdm9pZAovLwovLyBCdXkgdGlja2V0cy4gTm90ZSB0aGlzIGNhbiBvbmx5IGJlIGNhbGxlZCBvbmNlIQovLyBJdCB3b3VsZCBiZSBwb3NzaWJsZSB0byBhbGxvdyBtdWx0aXBsZSBwdXJjaGFzZXMsIGJ1dAovLyBmb3Igc2ltcGxpY2l0eSwgb25seSBvbmUgcHVyY2hhc2UgaXMgYWxsb3dlZC4KLy8KLy8gQHBhcmFtIHBheW1lbnQgVGhlIHBheW1lbnQgZm9yIHRoZSB0aWNrZXRzCi8vIEBwYXJhbSBxdWFuaXR5IFRoZSBudW1iZXIgb2YgdGlja2V0cyB0byBidXkKLy8KLy8gQHJldHVybnMgVGhlIHRvdGFsIG51bWJlciBvZiB0aWNrZXRzIG93bmVkIGJ5IHRoZSBzZW5kZXIKYWJpX3JvdXRlX2J1eVRpY2tldHM6CgkvLyBxdWFudGl0eTogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gcGF5bWVudDogcGF5Cgl0eG4gR3JvdXBJbmRleAoJaW50IDEKCS0KCWR1cAoJZ3R4bnMgVHlwZUVudW0KCWludCBwYXkKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIGJ1eVRpY2tldHModWludDY0LHBheSl2b2lkCgljYWxsc3ViIGJ1eVRpY2tldHMKCWludCAxCglyZXR1cm4KCmJ1eVRpY2tldHM6Cglwcm90byAyIDA7IGJ5dGUgMHg7IGR1cG4gMwoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo5NgoJLy8gYXNzZXJ0KGdsb2JhbHMucm91bmQgPCB0aGlzLmVuZFJvdW5kLnZhbHVlKQoJZ2xvYmFsIFJvdW5kCglieXRlIDB4NjU2ZTY0NTI2Zjc1NmU2NCAvLyAiZW5kUm91bmQiCglhcHBfZ2xvYmFsX2dldAoJPAoJYXNzZXJ0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjk3CgkvLyBhc3NlcnQocXVhbnRpdHkgPiAwKQoJZnJhbWVfZGlnIC0yIC8vIHF1YW50aXR5OiB1aW50NjQKCWludCAwCgk+Cglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6OTkKCS8vIGFzc2VydCghdGhpcy50aWNrZXRzKHBheW1lbnQuc2VuZGVyKS5leGlzdHMpCglmcmFtZV9kaWcgLTEgLy8gcGF5bWVudDogcGF5CglndHhucyBTZW5kZXIKCWJveF9sZW4KCXN3YXAKCXBvcAoJIQoJYXNzZXJ0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEwMQoJLy8gbmV3VG90YWwgPSB0aGlzLnRvdGFsVGlja2V0cy52YWx1ZSArIHF1YW50aXR5ICsgMQoJYnl0ZSAweDc0NmY3NDYxNmM1NDY5NjM2YjY1NzQ3MyAvLyAidG90YWxUaWNrZXRzIgoJYXBwX2dsb2JhbF9nZXQKCWZyYW1lX2RpZyAtMiAvLyBxdWFudGl0eTogdWludDY0CgkrCglpbnQgMQoJKwoJZnJhbWVfYnVyeSAxIC8vIG5ld1RvdGFsOiB1aW50NjQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTAzCgkvLyBwcmVNQlIgPSB0aGlzLmFwcC5hZGRyZXNzLm1pbkJhbGFuY2UKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCglhY2N0X3BhcmFtc19nZXQgQWNjdE1pbkJhbGFuY2UKCWFzc2VydAoJZnJhbWVfYnVyeSAyIC8vIHByZU1CUjogdWludDY0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEwNAoJLy8gdGhpcy50aWNrZXRzKHBheW1lbnQuc2VuZGVyKS52YWx1ZSA9IHsgc3RhcnQ6IHRoaXMudG90YWxUaWNrZXRzLnZhbHVlLCBlbmQ6IG5ld1RvdGFsIC0gMSB9CglmcmFtZV9kaWcgLTEgLy8gcGF5bWVudDogcGF5CglndHhucyBTZW5kZXIKCWJ5dGUgMHg3NDZmNzQ2MTZjNTQ2OTYzNmI2NTc0NzMgLy8gInRvdGFsVGlja2V0cyIKCWFwcF9nbG9iYWxfZ2V0CglpdG9iCglmcmFtZV9kaWcgMSAvLyBuZXdUb3RhbDogdWludDY0CglpbnQgMQoJLQoJaXRvYgoJY29uY2F0Cglib3hfcHV0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEwNQoJLy8gbWJyRGVsdGEgPSB0aGlzLmFwcC5hZGRyZXNzLm1pbkJhbGFuY2UgLSBwcmVNQlIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCglhY2N0X3BhcmFtc19nZXQgQWNjdE1pbkJhbGFuY2UKCWFzc2VydAoJZnJhbWVfZGlnIDIgLy8gcHJlTUJSOiB1aW50NjQKCS0KCWZyYW1lX2J1cnkgMyAvLyBtYnJEZWx0YTogdWludDY0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEwNwoJLy8gdmVyaWZ5VHhuKHBheW1lbnQsIHsKCS8vICAgICAgIGFtb3VudDogdGhpcy50aWNrZXRQcmljZS52YWx1ZSAqIHF1YW50aXR5ICsgbWJyRGVsdGEsCgkvLyAgICAgICBzZW5kZXI6IHRoaXMudHhuLnNlbmRlciwKCS8vICAgICAgIHJlY2VpdmVyOiB0aGlzLmFwcC5hZGRyZXNzLAoJLy8gICAgIH0pCgkvLyB2ZXJpZnkgYW1vdW50CglmcmFtZV9kaWcgLTEgLy8gcGF5bWVudDogcGF5CglndHhucyBBbW91bnQKCWJ5dGUgMHg3NDY5NjM2YjY1NzQ1MDcyNjk2MzY1IC8vICJ0aWNrZXRQcmljZSIKCWFwcF9nbG9iYWxfZ2V0CglmcmFtZV9kaWcgLTIgLy8gcXVhbnRpdHk6IHVpbnQ2NAoJKgoJZnJhbWVfZGlnIDMgLy8gbWJyRGVsdGE6IHVpbnQ2NAoJKwoJPT0KCWFzc2VydAoKCS8vIHZlcmlmeSBzZW5kZXIKCWZyYW1lX2RpZyAtMSAvLyBwYXltZW50OiBwYXkKCWd0eG5zIFNlbmRlcgoJdHhuIFNlbmRlcgoJPT0KCWFzc2VydAoKCS8vIHZlcmlmeSByZWNlaXZlcgoJZnJhbWVfZGlnIC0xIC8vIHBheW1lbnQ6IHBheQoJZ3R4bnMgUmVjZWl2ZXIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCgk9PQoJYXNzZXJ0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjExMwoJLy8gdGhpcy50b3RhbFRpY2tldHMudmFsdWUgPSBuZXdUb3RhbAoJYnl0ZSAweDc0NmY3NDYxNmM1NDY5NjM2YjY1NzQ3MyAvLyAidG90YWxUaWNrZXRzIgoJZnJhbWVfZGlnIDEgLy8gbmV3VG90YWw6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCXJldHN1YgoKZ2V0UmFuZG9tQnl0ZXM6Cglwcm90byAwIDAKCgkvLyBpZjBfY29uZGl0aW9uCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTE4CgkvLyB0aGlzLnJhbmRvbUJ5dGVzLmV4aXN0cwoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJYnl0ZSAweDcyNjE2ZTY0NmY2ZDQyNzk3NDY1NzMgLy8gInJhbmRvbUJ5dGVzIgoJYXBwX2dsb2JhbF9nZXRfZXgKCXN3YXAKCXBvcAoJYnogaWYwX2Vsc2UKCgkvLyBpZjBfY29uc2VxdWVudAoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjExOQoJLy8gdGhpcy5yYW5kb21CeXRlcy52YWx1ZSA9IHNoYTI1Nih0aGlzLnJhbmRvbUJ5dGVzLnZhbHVlKSBhcyBieXRlcwoJYnl0ZSAweDcyNjE2ZTY0NmY2ZDQyNzk3NDY1NzMgLy8gInJhbmRvbUJ5dGVzIgoJYnl0ZSAweDcyNjE2ZTY0NmY2ZDQyNzk3NDY1NzMgLy8gInJhbmRvbUJ5dGVzIgoJYXBwX2dsb2JhbF9nZXQKCXNoYTI1NgoJYXBwX2dsb2JhbF9wdXQKCWIgaWYwX2VuZAoKaWYwX2Vsc2U6CgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTIxCgkvLyB0aGlzLnJhbmRvbUJ5dGVzLnZhbHVlID0gc2VuZE1ldGhvZENhbGw8W3VpbnQ2NCwgYnl0ZXNdLCBieXRlcz4oewoJLy8gICAgICAgICBuYW1lOiAnbXVzdF9nZXQnLAoJLy8gICAgICAgICBtZXRob2RBcmdzOiBbdGhpcy5kcmF3Um91bmQudmFsdWUsICcnXSwKCS8vICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwbGljYXRpb24uZnJvbUlEKHRoaXMucmFuZG9tbmVzc09yYWNsZS52YWx1ZSksCgkvLyAgICAgICAgIGZlZTogMCwKCS8vICAgICAgICAgb25Db21wbGV0aW9uOiBPbkNvbXBsZXRpb24uTm9PcCwKCS8vICAgICAgIH0pCglieXRlIDB4NzI2MTZlNjQ2ZjZkNDI3OTc0NjU3MyAvLyAicmFuZG9tQnl0ZXMiCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJtdXN0X2dldCh1aW50NjQsYnl0ZVtdKWJ5dGVbXSIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEyMwoJLy8gbWV0aG9kQXJnczogW3RoaXMuZHJhd1JvdW5kLnZhbHVlLCAnJ10KCWJ5dGUgMHg2NDcyNjE3NzUyNmY3NTZlNjQgLy8gImRyYXdSb3VuZCIKCWFwcF9nbG9iYWxfZ2V0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJYnl0ZSAweDAwMDAKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEyNAoJLy8gYXBwbGljYXRpb25JRDogQXBwbGljYXRpb24uZnJvbUlEKHRoaXMucmFuZG9tbmVzc09yYWNsZS52YWx1ZSkKCWJ5dGUgMHg3MjYxNmU2NDZmNmQ2ZTY1NzM3MzRmNzI2MTYzNmM2NSAvLyAicmFuZG9tbmVzc09yYWNsZSIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTI1CgkvLyBmZWU6IDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxMjYKCS8vIG9uQ29tcGxldGlvbjogT25Db21wbGV0aW9uLk5vT3AKCWludCAwIC8vIE5vT3AKCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglhcHBfZ2xvYmFsX3B1dAoKaWYwX2VuZDoKCXJldHN1YgoKLy8gZHJhdyhhcHBsaWNhdGlvbilib29sCi8vCi8vIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bnVzZWQtdmFycwphYmlfcm91dGVfZHJhdzoKCS8vIF9vcmFjbGVSZWZlcmVuY2U6IGFwcGxpY2F0aW9uCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgl0eG5hcyBBcHBsaWNhdGlvbnMKCgkvLyBleGVjdXRlIGRyYXcoYXBwbGljYXRpb24pYm9vbAoJY2FsbHN1YiBkcmF3CglpbnQgMQoJcmV0dXJuCgpkcmF3OgoJcHJvdG8gMSAwOyBieXRlIDB4OyBkdXBuIDQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTM1CgkvLyBhc3NlcnQoIXRoaXMud2lubmluZ1RpY2tldC5leGlzdHMpCgl0eG5hIEFwcGxpY2F0aW9ucyAwCglieXRlIDB4Nzc2OTZlNmU2OTZlNjc1NDY5NjM2YjY1NzQgLy8gIndpbm5pbmdUaWNrZXQiCglhcHBfZ2xvYmFsX2dldF9leAoJc3dhcAoJcG9wCgkhCglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTM2CgkvLyB0aGlzLmdldFJhbmRvbUJ5dGVzKCkKCWNhbGxzdWIgZ2V0UmFuZG9tQnl0ZXMKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTQwCgkvLyBuID0gdGhpcy50b3RhbFRpY2tldHMudmFsdWUKCWJ5dGUgMHg3NDZmNzQ2MTZjNTQ2OTYzNmI2NTc0NzMgLy8gInRvdGFsVGlja2V0cyIKCWFwcF9nbG9iYWxfZ2V0CglmcmFtZV9idXJ5IDEgLy8gbjogdWludDY0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE0MgoJLy8gb2Zmc2V0ID0gMAoJaW50IDAKCWZyYW1lX2J1cnkgMyAvLyBvZmZzZXQ6IHVpbnQ2NAoKZG9fd2hpbGVfMDoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxNDYKCS8vIHggPSBleHRyYWN0X3VpbnQ2NCh0aGlzLnJhbmRvbUJ5dGVzLnZhbHVlLCBvZmZzZXQpCglieXRlIDB4NzI2MTZlNjQ2ZjZkNDI3OTc0NjU3MyAvLyAicmFuZG9tQnl0ZXMiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIDMgLy8gb2Zmc2V0OiB1aW50NjQKCWV4dHJhY3RfdWludDY0CglmcmFtZV9idXJ5IDIgLy8geDogdWludDY0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE0OAoJLy8gb2Zmc2V0ID0gb2Zmc2V0ICsgOAoJZnJhbWVfZGlnIDMgLy8gb2Zmc2V0OiB1aW50NjQKCWludCA4CgkrCglmcmFtZV9idXJ5IDMgLy8gb2Zmc2V0OiB1aW50NjQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTUwCgkvLyBtYXhDb25kaXRpb24gPSB4ID4gUkFORF9NQVggLSAoKChSQU5EX01BWCAlIG4pICsgMSkgJSBuKQoJZnJhbWVfZGlnIDIgLy8geDogdWludDY0CglpbnQgMThfNDQ2Xzc0NF8wNzNfNzA5XzU1MV82MTUKCWludCAxOF80NDZfNzQ0XzA3M183MDlfNTUxXzYxNQoJZnJhbWVfZGlnIDEgLy8gbjogdWludDY0CgklCglpbnQgMQoJKwoJZnJhbWVfZGlnIDEgLy8gbjogdWludDY0CgklCgktCgk+CglmcmFtZV9idXJ5IDQgLy8gbWF4Q29uZGl0aW9uOiBib29sCglmcmFtZV9kaWcgNCAvLyBtYXhDb25kaXRpb246IGJvb2wKCWR1cAoJYnogc2tpcF9hbmQwCglmcmFtZV9kaWcgMyAvLyBvZmZzZXQ6IHVpbnQ2NAoJaW50IDMyCgk8CgkmJgoKc2tpcF9hbmQwOgoJYm56IGRvX3doaWxlXzAKCgkvLyBpZjFfY29uZGl0aW9uCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTUzCgkvLyBtYXhDb25kaXRpb24KCWZyYW1lX2RpZyA0IC8vIG1heENvbmRpdGlvbjogYm9vbAoJYnogaWYxX2VuZAoKCS8vIGlmMV9jb25zZXF1ZW50CgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTUzCgkvLyByZXR1cm4gZmFsc2U7CglpbnQgMAoJYnl0ZSAweDAwCglpbnQgMAoJdW5jb3ZlciAyCglzZXRiaXQKCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKaWYxX2VuZDoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxNTUKCS8vIHRoaXMud2lubmluZ1RpY2tldC52YWx1ZSA9IHggJSBuCglieXRlIDB4Nzc2OTZlNmU2OTZlNjc1NDY5NjM2YjY1NzQgLy8gIndpbm5pbmdUaWNrZXQiCglmcmFtZV9kaWcgMiAvLyB4OiB1aW50NjQKCWZyYW1lX2RpZyAxIC8vIG46IHVpbnQ2NAoJJQoJYXBwX2dsb2JhbF9wdXQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTU2CgkvLyByZXR1cm4gdHJ1ZTsKCWludCAxCglieXRlIDB4MDAKCWludCAwCgl1bmNvdmVyIDIKCXNldGJpdAoJYnl0ZSAweDE1MWY3Yzc1Cglzd2FwCgljb25jYXQKCWxvZwoJcmV0c3ViCgovLyBjbGFpbSgpdm9pZAovLwovLyBTZW5kIHRoZSBhc3NldCB0byB0aGUgdGhlIHNlbmRlciBpZiB0aGV5IGhhdmUgdGhlIHdpbm5pbmcgdGlja2V0CmFiaV9yb3V0ZV9jbGFpbToKCS8vIGV4ZWN1dGUgY2xhaW0oKXZvaWQKCWNhbGxzdWIgY2xhaW0KCWludCAxCglyZXR1cm4KCmNsYWltOgoJcHJvdG8gMCAwOyBieXRlIDB4OyBkdXBuIDEKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTYxCgkvLyB0aWNrZXRSYW5nZSA9IHRoaXMudGlja2V0cyh0aGlzLnR4bi5zZW5kZXIpLnZhbHVlCgl0eG4gU2VuZGVyCglmcmFtZV9idXJ5IDEgLy8gc3RvcmFnZSBrZXkvL3RpY2tldFJhbmdlCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE2MwoJLy8gYXNzZXJ0KHRpY2tldFJhbmdlLnN0YXJ0IDw9IHRoaXMud2lubmluZ1RpY2tldC52YWx1ZSkKCWZyYW1lX2RpZyAxIC8vIHN0b3JhZ2Uga2V5Ly90aWNrZXRSYW5nZQoJYm94X2dldAoJYXNzZXJ0CglleHRyYWN0IDAgOAoJYnRvaQoJYnl0ZSAweDc3Njk2ZTZlNjk2ZTY3NTQ2OTYzNmI2NTc0IC8vICJ3aW5uaW5nVGlja2V0IgoJYXBwX2dsb2JhbF9nZXQKCTw9Cglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTY0CgkvLyBhc3NlcnQodGlja2V0UmFuZ2UuZW5kID49IHRoaXMud2lubmluZ1RpY2tldC52YWx1ZSkKCWZyYW1lX2RpZyAxIC8vIHN0b3JhZ2Uga2V5Ly90aWNrZXRSYW5nZQoJYm94X2dldAoJYXNzZXJ0CglleHRyYWN0IDggOAoJYnRvaQoJYnl0ZSAweDc3Njk2ZTZlNjk2ZTY3NTQ2OTYzNmI2NTc0IC8vICJ3aW5uaW5nVGlja2V0IgoJYXBwX2dsb2JhbF9nZXQKCT49Cglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTY2CgkvLyBzZW5kQXNzZXRUcmFuc2Zlcih7CgkvLyAgICAgICBhc3NldFJlY2VpdmVyOiB0aGlzLnR4bi5zZW5kZXIsCgkvLyAgICAgICB4ZmVyQXNzZXQ6IHRoaXMuYXNzZXQudmFsdWUsCgkvLyAgICAgICBhc3NldEFtb3VudDogdGhpcy5hcHAuYWRkcmVzcy5hc3NldEJhbGFuY2UodGhpcy5hc3NldC52YWx1ZSksCgkvLyAgICAgICBhc3NldENsb3NlVG86IHRoaXMudHhuLnNlbmRlciwKCS8vICAgICAgIGZlZTogMCwKCS8vICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGF4ZmVyCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE2NwoJLy8gYXNzZXRSZWNlaXZlcjogdGhpcy50eG4uc2VuZGVyCgl0eG4gU2VuZGVyCglpdHhuX2ZpZWxkIEFzc2V0UmVjZWl2ZXIKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTY4CgkvLyB4ZmVyQXNzZXQ6IHRoaXMuYXNzZXQudmFsdWUKCWJ5dGUgMHg2MTczNzM2NTc0IC8vICJhc3NldCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIFhmZXJBc3NldAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxNjkKCS8vIGFzc2V0QW1vdW50OiB0aGlzLmFwcC5hZGRyZXNzLmFzc2V0QmFsYW5jZSh0aGlzLmFzc2V0LnZhbHVlKQoJZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKCWJ5dGUgMHg2MTczNzM2NTc0IC8vICJhc3NldCIKCWFwcF9nbG9iYWxfZ2V0Cglhc3NldF9ob2xkaW5nX2dldCBBc3NldEJhbGFuY2UKCWFzc2VydAoJaXR4bl9maWVsZCBBc3NldEFtb3VudAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxNzAKCS8vIGFzc2V0Q2xvc2VUbzogdGhpcy50eG4uc2VuZGVyCgl0eG4gU2VuZGVyCglpdHhuX2ZpZWxkIEFzc2V0Q2xvc2VUbwoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxNzEKCS8vIGZlZTogMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJcmV0c3ViCgovLyBnZXRSZWZ1bmQoKXZvaWQKLy8KLy8gQWxsb3dzIHB1cmNoYXNlcnMgdG8gZ2V0IGEgcmVmdW5kIGlmIHRoZSB3aW5uaW5nIHRpY2tldCBoYXMgbm90IGJlZW4gZHJhd24KLy8gYW5kIDE1MTIgcm91bmRzIGhhdmUgcGFzc2VkIHNpbmNlIHRoZSBkcmF3IHJvdW5kLCBtZWFuaW5nIHRoZSBvcmFjbGUgbm8KLy8gbG9uZ2VyIGhhcyB0aGUgZGF0YSBmb3IgdGhlIGRyYXcgcm91bmQKYWJpX3JvdXRlX2dldFJlZnVuZDoKCS8vIGV4ZWN1dGUgZ2V0UmVmdW5kKCl2b2lkCgljYWxsc3ViIGdldFJlZnVuZAoJaW50IDEKCXJldHVybgoKZ2V0UmVmdW5kOgoJcHJvdG8gMCAwOyBieXRlIDB4OyBkdXBuIDIKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTgxCgkvLyBhc3NlcnQoIXRoaXMud2lubmluZ1RpY2tldC5leGlzdHMpCgl0eG5hIEFwcGxpY2F0aW9ucyAwCglieXRlIDB4Nzc2OTZlNmU2OTZlNjc1NDY5NjM2YjY1NzQgLy8gIndpbm5pbmdUaWNrZXQiCglhcHBfZ2xvYmFsX2dldF9leAoJc3dhcAoJcG9wCgkhCglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTgyCgkvLyBhc3NlcnQoZ2xvYmFscy5yb3VuZCA+IHRoaXMuZHJhd1JvdW5kLnZhbHVlICsgMTUxMikKCWdsb2JhbCBSb3VuZAoJYnl0ZSAweDY0NzI2MTc3NTI2Zjc1NmU2NCAvLyAiZHJhd1JvdW5kIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxNTEyCgkrCgk+Cglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTg0CgkvLyB0aWNrZXRSYW5nZSA9IHRoaXMudGlja2V0cyh0aGlzLnR4bi5zZW5kZXIpLnZhbHVlCgl0eG4gU2VuZGVyCglmcmFtZV9idXJ5IDEgLy8gc3RvcmFnZSBrZXkvL3RpY2tldFJhbmdlCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE4NQoJLy8gdGlja2V0Q291bnQgPSB0aWNrZXRSYW5nZS5lbmQgLSB0aWNrZXRSYW5nZS5zdGFydCArIDEKCWZyYW1lX2RpZyAxIC8vIHN0b3JhZ2Uga2V5Ly90aWNrZXRSYW5nZQoJYm94X2dldAoJYXNzZXJ0CglleHRyYWN0IDggOAoJYnRvaQoJZnJhbWVfZGlnIDEgLy8gc3RvcmFnZSBrZXkvL3RpY2tldFJhbmdlCglib3hfZ2V0Cglhc3NlcnQKCWV4dHJhY3QgMCA4CglidG9pCgktCglpbnQgMQoJKwoJZnJhbWVfYnVyeSAyIC8vIHRpY2tldENvdW50OiB1aW50NjQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTg3CgkvLyB0aGlzLnRpY2tldHModGhpcy50eG4uc2VuZGVyKS5kZWxldGUoKQoJdHhuIFNlbmRlcgoJYm94X2RlbAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxODkKCS8vIHNlbmRQYXltZW50KHsKCS8vICAgICAgIGFtb3VudDogdGhpcy50aWNrZXRQcmljZS52YWx1ZSAqIHRpY2tldENvdW50LAoJLy8gICAgICAgcmVjZWl2ZXI6IHRoaXMudHhuLnNlbmRlciwKCS8vICAgICAgIGZlZTogMCwKCS8vICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IHBheQoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxOTAKCS8vIGFtb3VudDogdGhpcy50aWNrZXRQcmljZS52YWx1ZSAqIHRpY2tldENvdW50CglieXRlIDB4NzQ2OTYzNmI2NTc0NTA3MjY5NjM2NSAvLyAidGlja2V0UHJpY2UiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIDIgLy8gdGlja2V0Q291bnQ6IHVpbnQ2NAoJKgoJaXR4bl9maWVsZCBBbW91bnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTkxCgkvLyByZWNlaXZlcjogdGhpcy50eG4uc2VuZGVyCgl0eG4gU2VuZGVyCglpdHhuX2ZpZWxkIFJlY2VpdmVyCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE5MgoJLy8gZmVlOiAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CglyZXRzdWIKCmNyZWF0ZV9Ob09wOgoJbWV0aG9kICJjcmVhdGVBcHBsaWNhdGlvbih1aW50NjQsdWludDY0KXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCBhYmlfcm91dGVfY3JlYXRlQXBwbGljYXRpb24KCWVycgoKY2FsbF9Ob09wOgoJbWV0aG9kICJzZXRBc3NldChhc3NldCl2b2lkIgoJbWV0aG9kICJzdGFydFJhZmZsZShheGZlcix1aW50NjQsdWludDY0KXZvaWQiCgltZXRob2QgImJ1eVRpY2tldHMocGF5LHVpbnQ2NCl2b2lkIgoJbWV0aG9kICJkcmF3KGFwcGxpY2F0aW9uKWJvb2wiCgltZXRob2QgImNsYWltKCl2b2lkIgoJbWV0aG9kICJnZXRSZWZ1bmQoKXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCBhYmlfcm91dGVfc2V0QXNzZXQgYWJpX3JvdXRlX3N0YXJ0UmFmZmxlIGFiaV9yb3V0ZV9idXlUaWNrZXRzIGFiaV9yb3V0ZV9kcmF3IGFiaV9yb3V0ZV9jbGFpbSBhYmlfcm91dGVfZ2V0UmVmdW5kCgllcnI=", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDk=" + }, + "contract": { + "name": "NFTRaffle", + "desc": "", + "methods": [ + { + "name": "createApplication", + "args": [ + { + "name": "ticketPrice", + "type": "uint64", + "desc": "The price of a single ticket (uALGO)" + }, + { + "name": "randomnessOracle", + "type": "uint64", + "desc": "The app ID of the randomness oracle" + } + ], + "desc": "Create the raffle", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "setAsset", + "args": [ + { + "name": "asset", + "type": "asset", + "desc": "The asset to be raffled" + } + ], + "desc": "Set the asset to be raffled", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "startRaffle", + "args": [ + { + "name": "axfer", + "type": "axfer", + "desc": "" + }, + { + "name": "end", + "type": "uint64", + "desc": "The round number when the raffle ends" + }, + { + "name": "draw", + "type": "uint64", + "desc": "The round number when the raffle is drawn" + } + ], + "desc": "Start the raffle", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "buyTickets", + "args": [ + { + "name": "payment", + "type": "pay", + "desc": "The payment for the tickets" + }, + { + "name": "quantity", + "type": "uint64", + "desc": "" + } + ], + "desc": "Buy tickets. Note this can only be called once!It would be possible to allow multiple purchases, butfor simplicity, only one purchase is allowed.", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "draw", + "args": [ + { + "name": "_oracleReference", + "type": "application", + "desc": "" + } + ], + "desc": "", + "returns": { + "type": "bool", + "desc": "" + } + }, + { + "name": "claim", + "args": [], + "desc": "Send the asset to the the sender if they have the winning ticket", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "getRefund", + "args": [], + "desc": "Allows purchasers to get a refund if the winning ticket has not been drawnand 1512 rounds have passed since the draw round, meaning the oracle nolonger has the data for the draw round", + "returns": { + "type": "void", + "desc": "" + } + } + ] + } +} + +/** + * Defines an onCompletionAction of 'no_op' + */ +export type OnCompleteNoOp = { onCompleteAction?: 'no_op' | OnApplicationComplete.NoOpOC } +/** + * Defines an onCompletionAction of 'opt_in' + */ +export type OnCompleteOptIn = { onCompleteAction: 'opt_in' | OnApplicationComplete.OptInOC } +/** + * Defines an onCompletionAction of 'close_out' + */ +export type OnCompleteCloseOut = { onCompleteAction: 'close_out' | OnApplicationComplete.CloseOutOC } +/** + * Defines an onCompletionAction of 'delete_application' + */ +export type OnCompleteDelApp = { onCompleteAction: 'delete_application' | OnApplicationComplete.DeleteApplicationOC } +/** + * Defines an onCompletionAction of 'update_application' + */ +export type OnCompleteUpdApp = { onCompleteAction: 'update_application' | OnApplicationComplete.UpdateApplicationOC } +/** + * A state record containing a single unsigned integer + */ +export type IntegerState = { + /** + * Gets the state value as a BigInt + */ + asBigInt(): bigint + /** + * Gets the state value as a number. + */ + asNumber(): number +} +/** + * A state record containing binary data + */ +export type BinaryState = { + /** + * Gets the state value as a Uint8Array + */ + asByteArray(): Uint8Array + /** + * Gets the state value as a string + */ + asString(): string +} + +/** + * Defines the types of available calls and state of the NftRaffle smart contract. + */ +export type NftRaffle = { + /** + * Maps method signatures / names to their argument and return types. + */ + methods: + & Record<'createApplication(uint64,uint64)void' | 'createApplication', { + argsObj: { + /** + * The price of a single ticket (uALGO) + */ + ticketPrice: bigint | number + /** + * The app ID of the randomness oracle + */ + randomnessOracle: bigint | number + } + argsTuple: [ticketPrice: bigint | number, randomnessOracle: bigint | number] + returns: void + }> + & Record<'setAsset(asset)void' | 'setAsset', { + argsObj: { + /** + * The asset to be raffled + */ + asset: number | bigint + } + argsTuple: [asset: number | bigint] + returns: void + }> + & Record<'startRaffle(axfer,uint64,uint64)void' | 'startRaffle', { + argsObj: { + axfer: TransactionToSign | Transaction | Promise + /** + * The round number when the raffle ends + */ + end: bigint | number + /** + * The round number when the raffle is drawn + */ + draw: bigint | number + } + argsTuple: [axfer: TransactionToSign | Transaction | Promise, end: bigint | number, draw: bigint | number] + returns: void + }> + & Record<'buyTickets(pay,uint64)void' | 'buyTickets', { + argsObj: { + /** + * The payment for the tickets + */ + payment: TransactionToSign | Transaction | Promise + quantity: bigint | number + } + argsTuple: [payment: TransactionToSign | Transaction | Promise, quantity: bigint | number] + returns: void + }> + & Record<'draw(application)bool' | 'draw', { + argsObj: { + _oracleReference: number | bigint + } + argsTuple: [_oracleReference: number | bigint] + returns: boolean + }> + & Record<'claim()void' | 'claim', { + argsObj: { + } + argsTuple: [] + returns: void + }> + & Record<'getRefund()void' | 'getRefund', { + argsObj: { + } + argsTuple: [] + returns: void + }> + /** + * Defines the shape of the global and local state of the application. + */ + state: { + global: { + 'randomnessOracle'?: IntegerState + 'ticketPrice'?: IntegerState + 'asset'?: IntegerState + 'endRound'?: IntegerState + 'drawRound'?: IntegerState + 'totalTickets'?: IntegerState + 'winningTicket'?: IntegerState + 'randomBytes'?: BinaryState + } + } +} +/** + * Defines the possible abi call signatures + */ +export type NftRaffleSig = keyof NftRaffle['methods'] +/** + * Defines an object containing all relevant parameters for a single call to the contract. Where TSignature is undefined, a bare call is made + */ +export type TypedCallParams = { + method: TSignature + methodArgs: TSignature extends undefined ? undefined : Array +} & AppClientCallCoreParams & CoreAppCallArgs +/** + * Defines the arguments required for a bare call + */ +export type BareCallArgs = Omit +/** + * Maps a method signature from the NftRaffle smart contract to the method's arguments in either tuple of struct form + */ +export type MethodArgs = NftRaffle['methods'][TSignature]['argsObj' | 'argsTuple'] +/** + * Maps a method signature from the NftRaffle smart contract to the method's return type + */ +export type MethodReturn = NftRaffle['methods'][TSignature]['returns'] + +/** + * A factory for available 'create' calls + */ +export type NftRaffleCreateCalls = (typeof NftRaffleCallFactory)['create'] +/** + * Defines supported create methods for this smart contract + */ +export type NftRaffleCreateCallParams = + | (TypedCallParams<'createApplication(uint64,uint64)void'> & (OnCompleteNoOp)) +/** + * Defines arguments required for the deploy method. + */ +export type NftRaffleDeployArgs = { + deployTimeParams?: TealTemplateParams + /** + * A delegate which takes a create call factory and returns the create call params for this smart contract + */ + createCall?: (callFactory: NftRaffleCreateCalls) => NftRaffleCreateCallParams +} + + +/** + * Exposes methods for constructing all available smart contract calls + */ +export abstract class NftRaffleCallFactory { + /** + * Gets available create call factories + */ + static get create() { + return { + /** + * Constructs a create call for the NFTRaffle smart contract using the createApplication(uint64,uint64)void ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + createApplication(args: MethodArgs<'createApplication(uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs & AppClientCompilationParams & (OnCompleteNoOp) = {}) { + return { + method: 'createApplication(uint64,uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.ticketPrice, args.randomnessOracle], + ...params, + } + }, + } + } + + /** + * Constructs a no op call for the setAsset(asset)void ABI method + * + * Set the asset to be raffled + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static setAsset(args: MethodArgs<'setAsset(asset)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'setAsset(asset)void' as const, + methodArgs: Array.isArray(args) ? args : [args.asset], + ...params, + } + } + /** + * Constructs a no op call for the startRaffle(axfer,uint64,uint64)void ABI method + * + * Start the raffle + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static startRaffle(args: MethodArgs<'startRaffle(axfer,uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'startRaffle(axfer,uint64,uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.axfer, args.end, args.draw], + ...params, + } + } + /** + * Constructs a no op call for the buyTickets(pay,uint64)void ABI method + * + * Buy tickets. Note this can only be called once!It would be possible to allow multiple purchases, butfor simplicity, only one purchase is allowed. + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static buyTickets(args: MethodArgs<'buyTickets(pay,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'buyTickets(pay,uint64)void' as const, + methodArgs: Array.isArray(args) ? args : [args.payment, args.quantity], + ...params, + } + } + /** + * Constructs a no op call for the draw(application)bool ABI method + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static draw(args: MethodArgs<'draw(application)bool'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'draw(application)bool' as const, + methodArgs: Array.isArray(args) ? args : [args._oracleReference], + ...params, + } + } + /** + * Constructs a no op call for the claim()void ABI method + * + * Send the asset to the the sender if they have the winning ticket + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static claim(args: MethodArgs<'claim()void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'claim()void' as const, + methodArgs: Array.isArray(args) ? args : [], + ...params, + } + } + /** + * Constructs a no op call for the getRefund()void ABI method + * + * Allows purchasers to get a refund if the winning ticket has not been drawnand 1512 rounds have passed since the draw round, meaning the oracle nolonger has the data for the draw round + * + * @param args Any args for the contract call + * @param params Any additional parameters for the call + * @returns A TypedCallParams object for the call + */ + static getRefund(args: MethodArgs<'getRefund()void'>, params: AppClientCallCoreParams & CoreAppCallArgs) { + return { + method: 'getRefund()void' as const, + methodArgs: Array.isArray(args) ? args : [], + ...params, + } + } +} + +/** + * A client to make calls to the NFTRaffle smart contract + */ +export class NftRaffleClient { + /** + * The underlying `ApplicationClient` for when you want to have more flexibility + */ + public readonly appClient: ApplicationClient + + private readonly sender: SendTransactionFrom | undefined + + /** + * Creates a new instance of `NftRaffleClient` + * + * @param appDetails appDetails The details to identify the app to deploy + * @param algod An algod client instance + */ + constructor(appDetails: AppDetails, private algod: Algodv2) { + this.sender = appDetails.sender + this.appClient = algokit.getAppClient({ + ...appDetails, + app: APP_SPEC + }, algod) + } + + /** + * Checks for decode errors on the AppCallTransactionResult and maps the return value to the specified generic type + * + * @param result The AppCallTransactionResult to be mapped + * @param returnValueFormatter An optional delegate to format the return value if required + * @returns The smart contract response with an updated return value + */ + protected mapReturnValue(result: AppCallTransactionResult, returnValueFormatter?: (value: any) => TReturn): AppCallTransactionResultOfType { + if(result.return?.decodeError) { + throw result.return.decodeError + } + const returnValue = result.return?.returnValue !== undefined && returnValueFormatter !== undefined + ? returnValueFormatter(result.return.returnValue) + : result.return?.returnValue as TReturn | undefined + return { ...result, return: returnValue } + } + + /** + * Calls the ABI method with the matching signature using an onCompletion code of NO_OP + * + * @param typedCallParams An object containing the method signature, args, and any other relevant parameters + * @param returnValueFormatter An optional delegate which when provided will be used to map non-undefined return values to the target type + * @returns The result of the smart contract call + */ + public async call(typedCallParams: TypedCallParams, returnValueFormatter?: (value: any) => MethodReturn) { + return this.mapReturnValue>(await this.appClient.call(typedCallParams), returnValueFormatter) + } + + /** + * Idempotently deploys the NFTRaffle smart contract. + * + * @param params The arguments for the contract calls and any additional parameters for the call + * @returns The deployment result + */ + public deploy(params: NftRaffleDeployArgs & AppClientDeployCoreParams = {}): ReturnType { + const createArgs = params.createCall?.(NftRaffleCallFactory.create) + return this.appClient.deploy({ + ...params, + createArgs, + createOnCompleteAction: createArgs?.onCompleteAction, + }) + } + + /** + * Gets available create methods + */ + public get create() { + const $this = this + return { + /** + * Creates a new instance of the NFTRaffle smart contract using the createApplication(uint64,uint64)void ABI method. + * + * @param args The arguments for the smart contract call + * @param params Any additional parameters for the call + * @returns The create result + */ + async createApplication(args: MethodArgs<'createApplication(uint64,uint64)void'>, params: AppClientCallCoreParams & AppClientCompilationParams & (OnCompleteNoOp) = {}): Promise>> { + return $this.mapReturnValue(await $this.appClient.create(NftRaffleCallFactory.create.createApplication(args, params))) + }, + } + } + + /** + * Makes a clear_state call to an existing instance of the NFTRaffle smart contract. + * + * @param args The arguments for the bare call + * @returns The clear_state result + */ + public clearState(args: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.appClient.clearState(args) + } + + /** + * Calls the setAsset(asset)void ABI method. + * + * Set the asset to be raffled + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public setAsset(args: MethodArgs<'setAsset(asset)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(NftRaffleCallFactory.setAsset(args, params)) + } + + /** + * Calls the startRaffle(axfer,uint64,uint64)void ABI method. + * + * Start the raffle + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public startRaffle(args: MethodArgs<'startRaffle(axfer,uint64,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(NftRaffleCallFactory.startRaffle(args, params)) + } + + /** + * Calls the buyTickets(pay,uint64)void ABI method. + * + * Buy tickets. Note this can only be called once!It would be possible to allow multiple purchases, butfor simplicity, only one purchase is allowed. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public buyTickets(args: MethodArgs<'buyTickets(pay,uint64)void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(NftRaffleCallFactory.buyTickets(args, params)) + } + + /** + * Calls the draw(application)bool ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public draw(args: MethodArgs<'draw(application)bool'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(NftRaffleCallFactory.draw(args, params)) + } + + /** + * Calls the claim()void ABI method. + * + * Send the asset to the the sender if they have the winning ticket + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public claim(args: MethodArgs<'claim()void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(NftRaffleCallFactory.claim(args, params)) + } + + /** + * Calls the getRefund()void ABI method. + * + * Allows purchasers to get a refund if the winning ticket has not been drawnand 1512 rounds have passed since the draw round, meaning the oracle nolonger has the data for the draw round + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The result of the call + */ + public getRefund(args: MethodArgs<'getRefund()void'>, params: AppClientCallCoreParams & CoreAppCallArgs = {}) { + return this.call(NftRaffleCallFactory.getRefund(args, params)) + } + + /** + * Extracts a binary state value out of an AppState dictionary + * + * @param state The state dictionary containing the state value + * @param key The key of the state value + * @returns A BinaryState instance containing the state value, or undefined if the key was not found + */ + private static getBinaryState(state: AppState, key: string): BinaryState | undefined { + const value = state[key] + if (!value) return undefined + if (!('valueRaw' in value)) + throw new Error(`Failed to parse state value for ${key}; received an int when expected a byte array`) + return { + asString(): string { + return value.value + }, + asByteArray(): Uint8Array { + return value.valueRaw + } + } + } + + /** + * Extracts a integer state value out of an AppState dictionary + * + * @param state The state dictionary containing the state value + * @param key The key of the state value + * @returns An IntegerState instance containing the state value, or undefined if the key was not found + */ + private static getIntegerState(state: AppState, key: string): IntegerState | undefined { + const value = state[key] + if (!value) return undefined + if ('valueRaw' in value) + throw new Error(`Failed to parse state value for ${key}; received a byte array when expected a number`) + return { + asBigInt() { + return typeof value.value === 'bigint' ? value.value : BigInt(value.value) + }, + asNumber(): number { + return typeof value.value === 'bigint' ? Number(value.value) : value.value + }, + } + } + + /** + * Returns the smart contract's global state wrapped in a strongly typed accessor with options to format the stored value + */ + public async getGlobalState(): Promise { + const state = await this.appClient.getGlobalState() + return { + get randomnessOracle() { + return NftRaffleClient.getIntegerState(state, 'randomnessOracle') + }, + get ticketPrice() { + return NftRaffleClient.getIntegerState(state, 'ticketPrice') + }, + get asset() { + return NftRaffleClient.getIntegerState(state, 'asset') + }, + get endRound() { + return NftRaffleClient.getIntegerState(state, 'endRound') + }, + get drawRound() { + return NftRaffleClient.getIntegerState(state, 'drawRound') + }, + get totalTickets() { + return NftRaffleClient.getIntegerState(state, 'totalTickets') + }, + get winningTicket() { + return NftRaffleClient.getIntegerState(state, 'winningTicket') + }, + get randomBytes() { + return NftRaffleClient.getBinaryState(state, 'randomBytes') + }, + } + } + + public compose(): NftRaffleComposer { + const client = this + const atc = new AtomicTransactionComposer() + let promiseChain:Promise = Promise.resolve() + const resultMappers: Array any)> = [] + return { + setAsset(args: MethodArgs<'setAsset(asset)void'>, params?: AppClientCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.setAsset(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + startRaffle(args: MethodArgs<'startRaffle(axfer,uint64,uint64)void'>, params?: AppClientCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.startRaffle(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + buyTickets(args: MethodArgs<'buyTickets(pay,uint64)void'>, params?: AppClientCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.buyTickets(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + draw(args: MethodArgs<'draw(application)bool'>, params?: AppClientCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.draw(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + claim(args: MethodArgs<'claim()void'>, params?: AppClientCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.claim(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + getRefund(args: MethodArgs<'getRefund()void'>, params?: AppClientCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.getRefund(args, {...params, sendParams: {...params?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + clearState(args?: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs) { + promiseChain = promiseChain.then(() => client.clearState({...args, sendParams: {...args?.sendParams, skipSending: true, atc}})) + resultMappers.push(undefined) + return this + }, + addTransaction(txn: TransactionWithSigner | TransactionToSign | Transaction | Promise, defaultSender?: SendTransactionFrom) { + promiseChain = promiseChain.then(async () => atc.addTransaction(await algokit.getTransactionWithSigner(txn, defaultSender ?? client.sender))) + return this + }, + async atc() { + await promiseChain + return atc + }, + async execute() { + await promiseChain + const result = await algokit.sendAtomicTransactionComposer({ atc, sendParams: {} }, client.algod) + return { + ...result, + returns: result.returns?.map((val, i) => resultMappers[i] !== undefined ? resultMappers[i]!(val.returnValue) : val.returnValue) + } + } + } as unknown as NftRaffleComposer + } +} +export type NftRaffleComposer = { + /** + * Calls the setAsset(asset)void ABI method. + * + * Set the asset to be raffled + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + setAsset(args: MethodArgs<'setAsset(asset)void'>, params?: AppClientCallCoreParams & CoreAppCallArgs): NftRaffleComposer<[...TReturns, MethodReturn<'setAsset(asset)void'>]> + + /** + * Calls the startRaffle(axfer,uint64,uint64)void ABI method. + * + * Start the raffle + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + startRaffle(args: MethodArgs<'startRaffle(axfer,uint64,uint64)void'>, params?: AppClientCallCoreParams & CoreAppCallArgs): NftRaffleComposer<[...TReturns, MethodReturn<'startRaffle(axfer,uint64,uint64)void'>]> + + /** + * Calls the buyTickets(pay,uint64)void ABI method. + * + * Buy tickets. Note this can only be called once!It would be possible to allow multiple purchases, butfor simplicity, only one purchase is allowed. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + buyTickets(args: MethodArgs<'buyTickets(pay,uint64)void'>, params?: AppClientCallCoreParams & CoreAppCallArgs): NftRaffleComposer<[...TReturns, MethodReturn<'buyTickets(pay,uint64)void'>]> + + /** + * Calls the draw(application)bool ABI method. + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + draw(args: MethodArgs<'draw(application)bool'>, params?: AppClientCallCoreParams & CoreAppCallArgs): NftRaffleComposer<[...TReturns, MethodReturn<'draw(application)bool'>]> + + /** + * Calls the claim()void ABI method. + * + * Send the asset to the the sender if they have the winning ticket + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + claim(args: MethodArgs<'claim()void'>, params?: AppClientCallCoreParams & CoreAppCallArgs): NftRaffleComposer<[...TReturns, MethodReturn<'claim()void'>]> + + /** + * Calls the getRefund()void ABI method. + * + * Allows purchasers to get a refund if the winning ticket has not been drawnand 1512 rounds have passed since the draw round, meaning the oracle nolonger has the data for the draw round + * + * @param args The arguments for the contract call + * @param params Any additional parameters for the call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + getRefund(args: MethodArgs<'getRefund()void'>, params?: AppClientCallCoreParams & CoreAppCallArgs): NftRaffleComposer<[...TReturns, MethodReturn<'getRefund()void'>]> + + /** + * Makes a clear_state call to an existing instance of the NFTRaffle smart contract. + * + * @param args The arguments for the bare call + * @returns The typed transaction composer so you can fluently chain multiple calls or call execute to execute all queued up transactions + */ + clearState(args?: BareCallArgs & AppClientCallCoreParams & CoreAppCallArgs): NftRaffleComposer<[...TReturns, undefined]> + + /** + * Adds a transaction to the composer + * + * @param txn One of: A TransactionWithSigner object (returned as is), a TransactionToSign object (signer is obtained from the signer property), a Transaction object (signer is extracted from the defaultSender parameter), an async SendTransactionResult returned by one of algokit utils helpers (signer is obtained from the defaultSender parameter) + * @param defaultSender The default sender to be used to obtain a signer where the object provided to the transaction parameter does not include a signer. + */ + addTransaction(txn: TransactionWithSigner | TransactionToSign | Transaction | Promise, defaultSender?: SendTransactionFrom): NftRaffleComposer + /** + * Returns the underlying AtomicTransactionComposer instance + */ + atc(): Promise + /** + * Executes the transaction group and returns an array of results + */ + execute(): Promise> +} +export type NftRaffleComposerResults = { + returns: TReturns + groupId: string + txIds: string[] + transactions: Transaction[] +} diff --git a/examples/raffle/artifacts/MockVRFBeacon.approval.teal b/examples/raffle/artifacts/MockVRFBeacon.approval.teal new file mode 100644 index 000000000..b4c4be579 --- /dev/null +++ b/examples/raffle/artifacts/MockVRFBeacon.approval.teal @@ -0,0 +1,76 @@ +#pragma version 9 + +// This TEAL was generated by TEALScript v0.65.0 +// https://github.com/algorandfoundation/TEALScript + +// This contract is compliant with and/or implements the following ARCs: [ ARC4 ] + +// The following ten lines of TEAL handle initial program flow +// This pattern is used to make it easy for anyone to parse the start of the program and determine if a specific action is allowed +// Here, action refers to the OnComplete in combination with whether the app is being created or called +// Every possible action for this contract is represented in the switch statement +// If the action is not implmented in the contract, its repsective branch will be "NOT_IMPLMENTED" which just contains "err" +txn ApplicationID +int 0 +> +int 6 +* +txn OnCompletion ++ +switch create_NoOp NOT_IMPLEMENTED NOT_IMPLEMENTED NOT_IMPLEMENTED NOT_IMPLEMENTED NOT_IMPLEMENTED call_NoOp + +NOT_IMPLEMENTED: + err + +// must_get(bytes,uint64)byte[] +abi_route_must_get: + // data: byte[] + txna ApplicationArgs 2 + extract 2 0 + + // _round: uint64 + txna ApplicationArgs 1 + btoi + + // execute must_get(bytes,uint64)byte[] + callsub must_get + int 1 + return + +must_get: + proto 2 0 + + // examples/raffle/raffle.algo.ts:200 + // return sha256(data + itob(globals.round)) as bytes; + frame_dig -2 // data: bytes + global Round + itob + concat + sha256 + dup + len + itob + extract 6 2 + swap + concat + byte 0x151f7c75 + swap + concat + log + retsub + +abi_route_createApplication: + int 1 + return + +create_NoOp: + method "createApplication()void" + txna ApplicationArgs 0 + match abi_route_createApplication + err + +call_NoOp: + method "must_get(uint64,byte[])byte[]" + txna ApplicationArgs 0 + match abi_route_must_get + err \ No newline at end of file diff --git a/examples/raffle/artifacts/MockVRFBeacon.arc32.json b/examples/raffle/artifacts/MockVRFBeacon.arc32.json new file mode 100644 index 000000000..16cebda37 --- /dev/null +++ b/examples/raffle/artifacts/MockVRFBeacon.arc32.json @@ -0,0 +1,80 @@ +{ + "hints": { + "must_get(uint64,byte[])byte[]": { + "call_config": { + "no_op": "CALL" + } + }, + "createApplication()void": { + "call_config": { + "no_op": "CREATE" + } + } + }, + "bare_call_config": { + "no_op": "NEVER", + "opt_in": "NEVER", + "close_out": "NEVER", + "update_application": "NEVER", + "delete_application": "NEVER" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": {}, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 0 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDkKCi8vIFRoaXMgVEVBTCB3YXMgZ2VuZXJhdGVkIGJ5IFRFQUxTY3JpcHQgdjAuNjUuMAovLyBodHRwczovL2dpdGh1Yi5jb20vYWxnb3JhbmRmb3VuZGF0aW9uL1RFQUxTY3JpcHQKCi8vIFRoaXMgY29udHJhY3QgaXMgY29tcGxpYW50IHdpdGggYW5kL29yIGltcGxlbWVudHMgdGhlIGZvbGxvd2luZyBBUkNzOiBbIEFSQzQgXQoKLy8gVGhlIGZvbGxvd2luZyB0ZW4gbGluZXMgb2YgVEVBTCBoYW5kbGUgaW5pdGlhbCBwcm9ncmFtIGZsb3cKLy8gVGhpcyBwYXR0ZXJuIGlzIHVzZWQgdG8gbWFrZSBpdCBlYXN5IGZvciBhbnlvbmUgdG8gcGFyc2UgdGhlIHN0YXJ0IG9mIHRoZSBwcm9ncmFtIGFuZCBkZXRlcm1pbmUgaWYgYSBzcGVjaWZpYyBhY3Rpb24gaXMgYWxsb3dlZAovLyBIZXJlLCBhY3Rpb24gcmVmZXJzIHRvIHRoZSBPbkNvbXBsZXRlIGluIGNvbWJpbmF0aW9uIHdpdGggd2hldGhlciB0aGUgYXBwIGlzIGJlaW5nIGNyZWF0ZWQgb3IgY2FsbGVkCi8vIEV2ZXJ5IHBvc3NpYmxlIGFjdGlvbiBmb3IgdGhpcyBjb250cmFjdCBpcyByZXByZXNlbnRlZCBpbiB0aGUgc3dpdGNoIHN0YXRlbWVudAovLyBJZiB0aGUgYWN0aW9uIGlzIG5vdCBpbXBsbWVudGVkIGluIHRoZSBjb250cmFjdCwgaXRzIHJlcHNlY3RpdmUgYnJhbmNoIHdpbGwgYmUgIk5PVF9JTVBMTUVOVEVEIiB3aGljaCBqdXN0IGNvbnRhaW5zICJlcnIiCnR4biBBcHBsaWNhdGlvbklECmludCAwCj4KaW50IDYKKgp0eG4gT25Db21wbGV0aW9uCisKc3dpdGNoIGNyZWF0ZV9Ob09wIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgTk9UX0lNUExFTUVOVEVEIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgY2FsbF9Ob09wCgpOT1RfSU1QTEVNRU5URUQ6CgllcnIKCi8vIG11c3RfZ2V0KGJ5dGVzLHVpbnQ2NClieXRlW10KYWJpX3JvdXRlX211c3RfZ2V0OgoJLy8gZGF0YTogYnl0ZVtdCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglleHRyYWN0IDIgMAoKCS8vIF9yb3VuZDogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gZXhlY3V0ZSBtdXN0X2dldChieXRlcyx1aW50NjQpYnl0ZVtdCgljYWxsc3ViIG11c3RfZ2V0CglpbnQgMQoJcmV0dXJuCgptdXN0X2dldDoKCXByb3RvIDIgMAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoyMDAKCS8vIHJldHVybiBzaGEyNTYoZGF0YSArIGl0b2IoZ2xvYmFscy5yb3VuZCkpIGFzIGJ5dGVzOwoJZnJhbWVfZGlnIC0yIC8vIGRhdGE6IGJ5dGVzCglnbG9iYWwgUm91bmQKCWl0b2IKCWNvbmNhdAoJc2hhMjU2CglkdXAKCWxlbgoJaXRvYgoJZXh0cmFjdCA2IDIKCXN3YXAKCWNvbmNhdAoJYnl0ZSAweDE1MWY3Yzc1Cglzd2FwCgljb25jYXQKCWxvZwoJcmV0c3ViCgphYmlfcm91dGVfY3JlYXRlQXBwbGljYXRpb246CglpbnQgMQoJcmV0dXJuCgpjcmVhdGVfTm9PcDoKCW1ldGhvZCAiY3JlYXRlQXBwbGljYXRpb24oKXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCBhYmlfcm91dGVfY3JlYXRlQXBwbGljYXRpb24KCWVycgoKY2FsbF9Ob09wOgoJbWV0aG9kICJtdXN0X2dldCh1aW50NjQsYnl0ZVtdKWJ5dGVbXSIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV9tdXN0X2dldAoJZXJy", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDk=" + }, + "contract": { + "name": "MockVRFBeacon", + "desc": "", + "methods": [ + { + "name": "must_get", + "args": [ + { + "name": "_round", + "type": "uint64", + "desc": "" + }, + { + "name": "data", + "type": "byte[]", + "desc": "" + } + ], + "desc": "", + "returns": { + "type": "byte[]", + "desc": "" + } + }, + { + "name": "createApplication", + "desc": "", + "returns": { + "type": "void", + "desc": "" + }, + "args": [] + } + ] + } +} \ No newline at end of file diff --git a/examples/raffle/artifacts/MockVRFBeacon.arc4.json b/examples/raffle/artifacts/MockVRFBeacon.arc4.json new file mode 100644 index 000000000..f1d48170a --- /dev/null +++ b/examples/raffle/artifacts/MockVRFBeacon.arc4.json @@ -0,0 +1,35 @@ +{ + "name": "MockVRFBeacon", + "desc": "", + "methods": [ + { + "name": "must_get", + "args": [ + { + "name": "_round", + "type": "uint64", + "desc": "" + }, + { + "name": "data", + "type": "byte[]", + "desc": "" + } + ], + "desc": "", + "returns": { + "type": "byte[]", + "desc": "" + } + }, + { + "name": "createApplication", + "desc": "", + "returns": { + "type": "void", + "desc": "" + }, + "args": [] + } + ] +} \ No newline at end of file diff --git a/examples/raffle/artifacts/MockVRFBeacon.clear.teal b/examples/raffle/artifacts/MockVRFBeacon.clear.teal new file mode 100644 index 000000000..858e5674c --- /dev/null +++ b/examples/raffle/artifacts/MockVRFBeacon.clear.teal @@ -0,0 +1 @@ +#pragma version 9 \ No newline at end of file diff --git a/examples/raffle/artifacts/MockVRFBeacon.src_map.json b/examples/raffle/artifacts/MockVRFBeacon.src_map.json new file mode 100644 index 000000000..134a0b463 --- /dev/null +++ b/examples/raffle/artifacts/MockVRFBeacon.src_map.json @@ -0,0 +1,371 @@ +[ + { + "teal": 1, + "source": 198, + "pc": [ + 0, + 1, + 2, + 3 + ] + }, + { + "teal": 13, + "source": 198, + "pc": [ + 4, + 5 + ] + }, + { + "teal": 14, + "source": 198, + "pc": [ + 6, + 7 + ] + }, + { + "teal": 15, + "source": 198, + "pc": [ + 8 + ] + }, + { + "teal": 16, + "source": 198, + "pc": [ + 9, + 10 + ] + }, + { + "teal": 17, + "source": 198, + "pc": [ + 11 + ] + }, + { + "teal": 18, + "source": 198, + "pc": [ + 12, + 13 + ] + }, + { + "teal": 19, + "source": 198, + "pc": [ + 14 + ] + }, + { + "teal": 20, + "source": 198, + "pc": [ + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30 + ] + }, + { + "teal": 23, + "source": 198, + "pc": [ + 31 + ] + }, + { + "teal": 28, + "source": 199, + "pc": [ + 32, + 33, + 34 + ] + }, + { + "teal": 29, + "source": 199, + "pc": [ + 35, + 36, + 37 + ] + }, + { + "teal": 32, + "source": 199, + "pc": [ + 38, + 39, + 40 + ] + }, + { + "teal": 33, + "source": 199, + "pc": [ + 41 + ] + }, + { + "teal": 36, + "source": 199, + "pc": [ + 42, + 43, + 44 + ] + }, + { + "teal": 37, + "source": 199, + "pc": [ + 45 + ] + }, + { + "teal": 38, + "source": 199, + "pc": [ + 46 + ] + }, + { + "teal": 41, + "source": 199, + "pc": [ + 47, + 48, + 49 + ] + }, + { + "teal": 45, + "source": 200, + "pc": [ + 50, + 51 + ] + }, + { + "teal": 46, + "source": 200, + "pc": [ + 52, + 53 + ] + }, + { + "teal": 47, + "source": 200, + "pc": [ + 54 + ] + }, + { + "teal": 48, + "source": 200, + "pc": [ + 55 + ] + }, + { + "teal": 49, + "source": 200, + "pc": [ + 56 + ] + }, + { + "teal": 50, + "source": 200, + "pc": [ + 57 + ] + }, + { + "teal": 51, + "source": 200, + "pc": [ + 58 + ] + }, + { + "teal": 52, + "source": 200, + "pc": [ + 59 + ] + }, + { + "teal": 53, + "source": 200, + "pc": [ + 60, + 61, + 62 + ] + }, + { + "teal": 54, + "source": 200, + "pc": [ + 63 + ] + }, + { + "teal": 55, + "source": 200, + "pc": [ + 64 + ] + }, + { + "teal": 56, + "source": 200, + "pc": [ + 65, + 66, + 67, + 68, + 69, + 70 + ] + }, + { + "teal": 57, + "source": 200, + "pc": [ + 71 + ] + }, + { + "teal": 58, + "source": 200, + "pc": [ + 72 + ] + }, + { + "teal": 59, + "source": 200, + "pc": [ + 73 + ] + }, + { + "teal": 60, + "source": 200, + "pc": [ + 74 + ] + }, + { + "teal": 63, + "source": 198, + "pc": [ + 75 + ] + }, + { + "teal": 64, + "source": 198, + "pc": [ + 76 + ] + }, + { + "teal": 67, + "source": 198, + "pc": [ + 77, + 78, + 79, + 80, + 81, + 82 + ] + }, + { + "teal": 68, + "source": 198, + "pc": [ + 83, + 84, + 85 + ] + }, + { + "teal": 69, + "source": 198, + "pc": [ + 86, + 87, + 88, + 89 + ] + }, + { + "teal": 70, + "source": 198, + "pc": [ + 90 + ] + }, + { + "teal": 73, + "source": 198, + "pc": [ + 91, + 92, + 93, + 94, + 95, + 96 + ] + }, + { + "teal": 74, + "source": 198, + "pc": [ + 97, + 98, + 99 + ] + }, + { + "teal": 75, + "source": 198, + "pc": [ + 100, + 101, + 102, + 103 + ] + }, + { + "teal": 76, + "source": 198, + "pc": [ + 104 + ] + } +] \ No newline at end of file diff --git a/examples/raffle/artifacts/NFTRaffle.abi.json b/examples/raffle/artifacts/NFTRaffle.abi.json new file mode 100644 index 000000000..cc4204984 --- /dev/null +++ b/examples/raffle/artifacts/NFTRaffle.abi.json @@ -0,0 +1,108 @@ +{ + "name": "NFTRaffle", + "desc": "", + "methods": [ + { + "name": "createApplication", + "args": [ + { + "name": "ticketPrice", + "type": "uint64", + "desc": "The price of a single ticket (uALGO)" + }, + { + "name": "randomnessOracle", + "type": "uint64", + "desc": "The app ID of the randomness oracle" + } + ], + "desc": "Create the raffle", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "setAsset", + "args": [ + { + "name": "asset", + "type": "asset", + "desc": "The asset to be raffled" + } + ], + "desc": "Set the asset to be raffled", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "startRaffle", + "args": [ + { + "name": "end", + "type": "uint64", + "desc": "The round number when the raffle ends" + }, + { + "name": "draw", + "type": "uint64", + "desc": "The round number when the raffle is drawn" + } + ], + "desc": "Start the raffle", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "buyTickets", + "args": [ + { + "name": "payment", + "type": "pay", + "desc": "The payment for the tickets" + }, + { + "name": "quanity", + "type": "uint64", + "desc": "The number of tickets to buy" + } + ], + "desc": "Buy tickets. Note this can only be called once!It would be possible to allow multiple purchases, butfor simplicity, only one purchase is allowed.", + "returns": { + "type": "void", + "desc": "The total number of tickets owned by the sender" + } + }, + { + "name": "draw", + "args": [], + "desc": "Draw the winning ticket", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "claim", + "args": [], + "desc": "Send the asset to the the sender if they have the winning ticket", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "getRefund", + "args": [], + "desc": "Allows purchasers to get a refund if the winning ticket has not been drawnand 1512 rounds have passed since the draw round, meaning the oracle nolonger has the data for the draw round", + "returns": { + "type": "void", + "desc": "" + } + } + ] +} \ No newline at end of file diff --git a/examples/raffle/artifacts/NFTRaffle.approval.teal b/examples/raffle/artifacts/NFTRaffle.approval.teal new file mode 100644 index 000000000..f1fda33d7 --- /dev/null +++ b/examples/raffle/artifacts/NFTRaffle.approval.teal @@ -0,0 +1,745 @@ +#pragma version 9 + +// This TEAL was generated by TEALScript v0.65.0 +// https://github.com/algorandfoundation/TEALScript + +// This contract is compliant with and/or implements the following ARCs: [ ARC4 ] + +// The following ten lines of TEAL handle initial program flow +// This pattern is used to make it easy for anyone to parse the start of the program and determine if a specific action is allowed +// Here, action refers to the OnComplete in combination with whether the app is being created or called +// Every possible action for this contract is represented in the switch statement +// If the action is not implmented in the contract, its repsective branch will be "NOT_IMPLMENTED" which just contains "err" +txn ApplicationID +int 0 +> +int 6 +* +txn OnCompletion ++ +switch create_NoOp NOT_IMPLEMENTED NOT_IMPLEMENTED NOT_IMPLEMENTED NOT_IMPLEMENTED NOT_IMPLEMENTED call_NoOp + +NOT_IMPLEMENTED: + err + +// createApplication(uint64,uint64)void +// +// Create the raffle +// +// @param ticketPrice The price of a single ticket (uALGO) +// @param randomnessOracle The app ID of the randomness oracle +abi_route_createApplication: + // randomnessOracle: uint64 + txna ApplicationArgs 2 + btoi + + // ticketPrice: uint64 + txna ApplicationArgs 1 + btoi + + // execute createApplication(uint64,uint64)void + callsub createApplication + int 1 + return + +createApplication: + proto 2 0 + + // examples/raffle/raffle.algo.ts:43 + // this.randomnessOracle.value = randomnessOracle + byte 0x72616e646f6d6e6573734f7261636c65 // "randomnessOracle" + frame_dig -2 // randomnessOracle: uint64 + app_global_put + + // examples/raffle/raffle.algo.ts:44 + // this.ticketPrice.value = ticketPrice + byte 0x7469636b65745072696365 // "ticketPrice" + frame_dig -1 // ticketPrice: uint64 + app_global_put + retsub + +// setAsset(asset)void +// +// Set the asset to be raffled +// +// @param asset The asset to be raffled +abi_route_setAsset: + // asset: asset + txna ApplicationArgs 1 + btoi + txnas Assets + + // execute setAsset(asset)void + callsub setAsset + int 1 + return + +setAsset: + proto 1 0 + + // examples/raffle/raffle.algo.ts:54 + // assert(!this.asset.exists) + txna Applications 0 + byte 0x6173736574 // "asset" + app_global_get_ex + swap + pop + ! + assert + + // examples/raffle/raffle.algo.ts:56 + // sendAssetTransfer({ + // assetReceiver: this.app.address, + // xferAsset: asset, + // assetAmount: 0, + // fee: 0, + // }) + itxn_begin + int axfer + itxn_field TypeEnum + + // examples/raffle/raffle.algo.ts:57 + // assetReceiver: this.app.address + global CurrentApplicationAddress + itxn_field AssetReceiver + + // examples/raffle/raffle.algo.ts:58 + // xferAsset: asset + frame_dig -1 // asset: asset + itxn_field XferAsset + + // examples/raffle/raffle.algo.ts:59 + // assetAmount: 0 + int 0 + itxn_field AssetAmount + + // examples/raffle/raffle.algo.ts:60 + // fee: 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + + // examples/raffle/raffle.algo.ts:63 + // this.asset.value = asset + byte 0x6173736574 // "asset" + frame_dig -1 // asset: asset + app_global_put + retsub + +// startRaffle(uint64,uint64,axfer)void +// +// Start the raffle +// +// @param end The round number when the raffle ends +// @param draw The round number when the raffle is drawn +abi_route_startRaffle: + // draw: uint64 + txna ApplicationArgs 2 + btoi + + // end: uint64 + txna ApplicationArgs 1 + btoi + + // axfer: axfer + txn GroupIndex + int 1 + - + dup + gtxns TypeEnum + int axfer + == + assert + + // execute startRaffle(uint64,uint64,axfer)void + callsub startRaffle + int 1 + return + +startRaffle: + proto 3 0 + + // examples/raffle/raffle.algo.ts:74 + // verifyTxn(axfer, { + // assetAmount: { greaterThan: 0 }, + // assetReceiver: this.app.address, + // xferAsset: this.asset.value, + // }) + // verify assetAmount + frame_dig -1 // axfer: axfer + gtxns AssetAmount + int 0 + > + assert + + // verify assetReceiver + frame_dig -1 // axfer: axfer + gtxns AssetReceiver + global CurrentApplicationAddress + == + assert + + // verify xferAsset + frame_dig -1 // axfer: axfer + gtxns XferAsset + byte 0x6173736574 // "asset" + app_global_get + == + assert + + // examples/raffle/raffle.algo.ts:80 + // assert(draw > end) + frame_dig -3 // draw: uint64 + frame_dig -2 // end: uint64 + > + assert + + // examples/raffle/raffle.algo.ts:81 + // this.endRound.value = end + byte 0x656e64526f756e64 // "endRound" + frame_dig -2 // end: uint64 + app_global_put + + // examples/raffle/raffle.algo.ts:82 + // this.drawRound.value = draw + byte 0x64726177526f756e64 // "drawRound" + frame_dig -3 // draw: uint64 + app_global_put + retsub + +// buyTickets(uint64,pay)void +// +// Buy tickets. Note this can only be called once! +// It would be possible to allow multiple purchases, but +// for simplicity, only one purchase is allowed. +// +// @param payment The payment for the tickets +// @param quanity The number of tickets to buy +// +// @returns The total number of tickets owned by the sender +abi_route_buyTickets: + // quantity: uint64 + txna ApplicationArgs 1 + btoi + + // payment: pay + txn GroupIndex + int 1 + - + dup + gtxns TypeEnum + int pay + == + assert + + // execute buyTickets(uint64,pay)void + callsub buyTickets + int 1 + return + +buyTickets: + proto 2 0; byte 0x; dupn 3 + + // examples/raffle/raffle.algo.ts:96 + // assert(globals.round < this.endRound.value) + global Round + byte 0x656e64526f756e64 // "endRound" + app_global_get + < + assert + + // examples/raffle/raffle.algo.ts:97 + // assert(quantity > 0) + frame_dig -2 // quantity: uint64 + int 0 + > + assert + + // examples/raffle/raffle.algo.ts:99 + // assert(!this.tickets(payment.sender).exists) + frame_dig -1 // payment: pay + gtxns Sender + box_len + swap + pop + ! + assert + + // examples/raffle/raffle.algo.ts:101 + // newTotal = this.totalTickets.value + quantity + 1 + byte 0x746f74616c5469636b657473 // "totalTickets" + app_global_get + frame_dig -2 // quantity: uint64 + + + int 1 + + + frame_bury 1 // newTotal: uint64 + + // examples/raffle/raffle.algo.ts:103 + // preMBR = this.app.address.minBalance + global CurrentApplicationAddress + acct_params_get AcctMinBalance + assert + frame_bury 2 // preMBR: uint64 + + // examples/raffle/raffle.algo.ts:104 + // this.tickets(payment.sender).value = { start: this.totalTickets.value, end: newTotal - 1 } + frame_dig -1 // payment: pay + gtxns Sender + byte 0x746f74616c5469636b657473 // "totalTickets" + app_global_get + itob + frame_dig 1 // newTotal: uint64 + int 1 + - + itob + concat + box_put + + // examples/raffle/raffle.algo.ts:105 + // mbrDelta = this.app.address.minBalance - preMBR + global CurrentApplicationAddress + acct_params_get AcctMinBalance + assert + frame_dig 2 // preMBR: uint64 + - + frame_bury 3 // mbrDelta: uint64 + + // examples/raffle/raffle.algo.ts:107 + // verifyTxn(payment, { + // amount: this.ticketPrice.value * quantity + mbrDelta, + // sender: this.txn.sender, + // receiver: this.app.address, + // }) + // verify amount + frame_dig -1 // payment: pay + gtxns Amount + byte 0x7469636b65745072696365 // "ticketPrice" + app_global_get + frame_dig -2 // quantity: uint64 + * + frame_dig 3 // mbrDelta: uint64 + + + == + assert + + // verify sender + frame_dig -1 // payment: pay + gtxns Sender + txn Sender + == + assert + + // verify receiver + frame_dig -1 // payment: pay + gtxns Receiver + global CurrentApplicationAddress + == + assert + + // examples/raffle/raffle.algo.ts:113 + // this.totalTickets.value = newTotal + byte 0x746f74616c5469636b657473 // "totalTickets" + frame_dig 1 // newTotal: uint64 + app_global_put + retsub + +getRandomBytes: + proto 0 0 + + // if0_condition + // examples/raffle/raffle.algo.ts:118 + // this.randomBytes.exists + txna Applications 0 + byte 0x72616e646f6d4279746573 // "randomBytes" + app_global_get_ex + swap + pop + bz if0_else + + // if0_consequent + // examples/raffle/raffle.algo.ts:119 + // this.randomBytes.value = sha256(this.randomBytes.value) as bytes + byte 0x72616e646f6d4279746573 // "randomBytes" + byte 0x72616e646f6d4279746573 // "randomBytes" + app_global_get + sha256 + app_global_put + b if0_end + +if0_else: + // examples/raffle/raffle.algo.ts:121 + // this.randomBytes.value = sendMethodCall<[uint64, bytes], bytes>({ + // name: 'must_get', + // methodArgs: [this.drawRound.value, ''], + // applicationID: Application.fromID(this.randomnessOracle.value), + // fee: 0, + // onCompletion: OnCompletion.NoOp, + // }) + byte 0x72616e646f6d4279746573 // "randomBytes" + itxn_begin + int appl + itxn_field TypeEnum + method "must_get(uint64,byte[])byte[]" + itxn_field ApplicationArgs + + // examples/raffle/raffle.algo.ts:123 + // methodArgs: [this.drawRound.value, ''] + byte 0x64726177526f756e64 // "drawRound" + app_global_get + itob + itxn_field ApplicationArgs + byte 0x0000 + itxn_field ApplicationArgs + + // examples/raffle/raffle.algo.ts:124 + // applicationID: Application.fromID(this.randomnessOracle.value) + byte 0x72616e646f6d6e6573734f7261636c65 // "randomnessOracle" + app_global_get + itxn_field ApplicationID + + // examples/raffle/raffle.algo.ts:125 + // fee: 0 + int 0 + itxn_field Fee + + // examples/raffle/raffle.algo.ts:126 + // onCompletion: OnCompletion.NoOp + int 0 // NoOp + itxn_field OnCompletion + + // Submit inner transaction + itxn_submit + itxn NumLogs + int 1 + - + itxnas Logs + extract 4 0 + app_global_put + +if0_end: + retsub + +// draw(application)bool +// +// // eslint-disable-next-line no-unused-vars +abi_route_draw: + // _oracleReference: application + txna ApplicationArgs 1 + btoi + txnas Applications + + // execute draw(application)bool + callsub draw + int 1 + return + +draw: + proto 1 0; byte 0x; dupn 4 + + // examples/raffle/raffle.algo.ts:135 + // assert(!this.winningTicket.exists) + txna Applications 0 + byte 0x77696e6e696e675469636b6574 // "winningTicket" + app_global_get_ex + swap + pop + ! + assert + + // examples/raffle/raffle.algo.ts:136 + // this.getRandomBytes() + callsub getRandomBytes + + // examples/raffle/raffle.algo.ts:140 + // n = this.totalTickets.value + byte 0x746f74616c5469636b657473 // "totalTickets" + app_global_get + frame_bury 1 // n: uint64 + + // examples/raffle/raffle.algo.ts:142 + // offset = 0 + int 0 + frame_bury 3 // offset: uint64 + +do_while_0: + // examples/raffle/raffle.algo.ts:146 + // x = extract_uint64(this.randomBytes.value, offset) + byte 0x72616e646f6d4279746573 // "randomBytes" + app_global_get + frame_dig 3 // offset: uint64 + extract_uint64 + frame_bury 2 // x: uint64 + + // examples/raffle/raffle.algo.ts:148 + // offset = offset + 8 + frame_dig 3 // offset: uint64 + int 8 + + + frame_bury 3 // offset: uint64 + + // examples/raffle/raffle.algo.ts:150 + // maxCondition = x > RAND_MAX - (((RAND_MAX % n) + 1) % n) + frame_dig 2 // x: uint64 + int 18_446_744_073_709_551_615 + int 18_446_744_073_709_551_615 + frame_dig 1 // n: uint64 + % + int 1 + + + frame_dig 1 // n: uint64 + % + - + > + frame_bury 4 // maxCondition: bool + frame_dig 4 // maxCondition: bool + dup + bz skip_and0 + frame_dig 3 // offset: uint64 + int 32 + < + && + +skip_and0: + bnz do_while_0 + + // if1_condition + // examples/raffle/raffle.algo.ts:153 + // maxCondition + frame_dig 4 // maxCondition: bool + bz if1_end + + // if1_consequent + // examples/raffle/raffle.algo.ts:153 + // return false; + int 0 + byte 0x00 + int 0 + uncover 2 + setbit + byte 0x151f7c75 + swap + concat + log + retsub + +if1_end: + // examples/raffle/raffle.algo.ts:155 + // this.winningTicket.value = x % n + byte 0x77696e6e696e675469636b6574 // "winningTicket" + frame_dig 2 // x: uint64 + frame_dig 1 // n: uint64 + % + app_global_put + + // examples/raffle/raffle.algo.ts:156 + // return true; + int 1 + byte 0x00 + int 0 + uncover 2 + setbit + byte 0x151f7c75 + swap + concat + log + retsub + +// claim()void +// +// Send the asset to the the sender if they have the winning ticket +abi_route_claim: + // execute claim()void + callsub claim + int 1 + return + +claim: + proto 0 0; byte 0x; dupn 1 + + // examples/raffle/raffle.algo.ts:161 + // ticketRange = this.tickets(this.txn.sender).value + txn Sender + frame_bury 1 // storage key//ticketRange + + // examples/raffle/raffle.algo.ts:163 + // assert(ticketRange.start <= this.winningTicket.value) + frame_dig 1 // storage key//ticketRange + box_get + assert + extract 0 8 + btoi + byte 0x77696e6e696e675469636b6574 // "winningTicket" + app_global_get + <= + assert + + // examples/raffle/raffle.algo.ts:164 + // assert(ticketRange.end >= this.winningTicket.value) + frame_dig 1 // storage key//ticketRange + box_get + assert + extract 8 8 + btoi + byte 0x77696e6e696e675469636b6574 // "winningTicket" + app_global_get + >= + assert + + // examples/raffle/raffle.algo.ts:166 + // sendAssetTransfer({ + // assetReceiver: this.txn.sender, + // xferAsset: this.asset.value, + // assetAmount: this.app.address.assetBalance(this.asset.value), + // assetCloseTo: this.txn.sender, + // fee: 0, + // }) + itxn_begin + int axfer + itxn_field TypeEnum + + // examples/raffle/raffle.algo.ts:167 + // assetReceiver: this.txn.sender + txn Sender + itxn_field AssetReceiver + + // examples/raffle/raffle.algo.ts:168 + // xferAsset: this.asset.value + byte 0x6173736574 // "asset" + app_global_get + itxn_field XferAsset + + // examples/raffle/raffle.algo.ts:169 + // assetAmount: this.app.address.assetBalance(this.asset.value) + global CurrentApplicationAddress + byte 0x6173736574 // "asset" + app_global_get + asset_holding_get AssetBalance + assert + itxn_field AssetAmount + + // examples/raffle/raffle.algo.ts:170 + // assetCloseTo: this.txn.sender + txn Sender + itxn_field AssetCloseTo + + // examples/raffle/raffle.algo.ts:171 + // fee: 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + retsub + +// getRefund()void +// +// Allows purchasers to get a refund if the winning ticket has not been drawn +// and 1512 rounds have passed since the draw round, meaning the oracle no +// longer has the data for the draw round +abi_route_getRefund: + // execute getRefund()void + callsub getRefund + int 1 + return + +getRefund: + proto 0 0; byte 0x; dupn 2 + + // examples/raffle/raffle.algo.ts:181 + // assert(!this.winningTicket.exists) + txna Applications 0 + byte 0x77696e6e696e675469636b6574 // "winningTicket" + app_global_get_ex + swap + pop + ! + assert + + // examples/raffle/raffle.algo.ts:182 + // assert(globals.round > this.drawRound.value + 1512) + global Round + byte 0x64726177526f756e64 // "drawRound" + app_global_get + int 1512 + + + > + assert + + // examples/raffle/raffle.algo.ts:184 + // ticketRange = this.tickets(this.txn.sender).value + txn Sender + frame_bury 1 // storage key//ticketRange + + // examples/raffle/raffle.algo.ts:185 + // ticketCount = ticketRange.end - ticketRange.start + 1 + frame_dig 1 // storage key//ticketRange + box_get + assert + extract 8 8 + btoi + frame_dig 1 // storage key//ticketRange + box_get + assert + extract 0 8 + btoi + - + int 1 + + + frame_bury 2 // ticketCount: uint64 + + // examples/raffle/raffle.algo.ts:187 + // this.tickets(this.txn.sender).delete() + txn Sender + box_del + + // examples/raffle/raffle.algo.ts:189 + // sendPayment({ + // amount: this.ticketPrice.value * ticketCount, + // receiver: this.txn.sender, + // fee: 0, + // }) + itxn_begin + int pay + itxn_field TypeEnum + + // examples/raffle/raffle.algo.ts:190 + // amount: this.ticketPrice.value * ticketCount + byte 0x7469636b65745072696365 // "ticketPrice" + app_global_get + frame_dig 2 // ticketCount: uint64 + * + itxn_field Amount + + // examples/raffle/raffle.algo.ts:191 + // receiver: this.txn.sender + txn Sender + itxn_field Receiver + + // examples/raffle/raffle.algo.ts:192 + // fee: 0 + int 0 + itxn_field Fee + + // Submit inner transaction + itxn_submit + retsub + +create_NoOp: + method "createApplication(uint64,uint64)void" + txna ApplicationArgs 0 + match abi_route_createApplication + err + +call_NoOp: + method "setAsset(asset)void" + method "startRaffle(axfer,uint64,uint64)void" + method "buyTickets(pay,uint64)void" + method "draw(application)bool" + method "claim()void" + method "getRefund()void" + txna ApplicationArgs 0 + match abi_route_setAsset abi_route_startRaffle abi_route_buyTickets abi_route_draw abi_route_claim abi_route_getRefund + err \ No newline at end of file diff --git a/examples/raffle/artifacts/NFTRaffle.arc32.json b/examples/raffle/artifacts/NFTRaffle.arc32.json new file mode 100644 index 000000000..3fd1cc85d --- /dev/null +++ b/examples/raffle/artifacts/NFTRaffle.arc32.json @@ -0,0 +1,222 @@ +{ + "hints": { + "createApplication(uint64,uint64)void": { + "call_config": { + "no_op": "CREATE" + } + }, + "setAsset(asset)void": { + "call_config": { + "no_op": "CALL" + } + }, + "startRaffle(axfer,uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "buyTickets(pay,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "draw(application)bool": { + "call_config": { + "no_op": "CALL" + } + }, + "claim()void": { + "call_config": { + "no_op": "CALL" + } + }, + "getRefund()void": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "NEVER", + "opt_in": "NEVER", + "close_out": "NEVER", + "update_application": "NEVER", + "delete_application": "NEVER" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": { + "randomnessOracle": { + "type": "uint64", + "key": "randomnessOracle" + }, + "ticketPrice": { + "type": "uint64", + "key": "ticketPrice" + }, + "asset": { + "type": "uint64", + "key": "asset" + }, + "endRound": { + "type": "uint64", + "key": "endRound" + }, + "drawRound": { + "type": "uint64", + "key": "drawRound" + }, + "totalTickets": { + "type": "uint64", + "key": "totalTickets" + }, + "winningTicket": { + "type": "uint64", + "key": "winningTicket" + }, + "randomBytes": { + "type": "bytes", + "key": "randomBytes" + } + }, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 1, + "num_uints": 7 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDkKCi8vIFRoaXMgVEVBTCB3YXMgZ2VuZXJhdGVkIGJ5IFRFQUxTY3JpcHQgdjAuNjUuMAovLyBodHRwczovL2dpdGh1Yi5jb20vYWxnb3JhbmRmb3VuZGF0aW9uL1RFQUxTY3JpcHQKCi8vIFRoaXMgY29udHJhY3QgaXMgY29tcGxpYW50IHdpdGggYW5kL29yIGltcGxlbWVudHMgdGhlIGZvbGxvd2luZyBBUkNzOiBbIEFSQzQgXQoKLy8gVGhlIGZvbGxvd2luZyB0ZW4gbGluZXMgb2YgVEVBTCBoYW5kbGUgaW5pdGlhbCBwcm9ncmFtIGZsb3cKLy8gVGhpcyBwYXR0ZXJuIGlzIHVzZWQgdG8gbWFrZSBpdCBlYXN5IGZvciBhbnlvbmUgdG8gcGFyc2UgdGhlIHN0YXJ0IG9mIHRoZSBwcm9ncmFtIGFuZCBkZXRlcm1pbmUgaWYgYSBzcGVjaWZpYyBhY3Rpb24gaXMgYWxsb3dlZAovLyBIZXJlLCBhY3Rpb24gcmVmZXJzIHRvIHRoZSBPbkNvbXBsZXRlIGluIGNvbWJpbmF0aW9uIHdpdGggd2hldGhlciB0aGUgYXBwIGlzIGJlaW5nIGNyZWF0ZWQgb3IgY2FsbGVkCi8vIEV2ZXJ5IHBvc3NpYmxlIGFjdGlvbiBmb3IgdGhpcyBjb250cmFjdCBpcyByZXByZXNlbnRlZCBpbiB0aGUgc3dpdGNoIHN0YXRlbWVudAovLyBJZiB0aGUgYWN0aW9uIGlzIG5vdCBpbXBsbWVudGVkIGluIHRoZSBjb250cmFjdCwgaXRzIHJlcHNlY3RpdmUgYnJhbmNoIHdpbGwgYmUgIk5PVF9JTVBMTUVOVEVEIiB3aGljaCBqdXN0IGNvbnRhaW5zICJlcnIiCnR4biBBcHBsaWNhdGlvbklECmludCAwCj4KaW50IDYKKgp0eG4gT25Db21wbGV0aW9uCisKc3dpdGNoIGNyZWF0ZV9Ob09wIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgTk9UX0lNUExFTUVOVEVEIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgY2FsbF9Ob09wCgpOT1RfSU1QTEVNRU5URUQ6CgllcnIKCi8vIGNyZWF0ZUFwcGxpY2F0aW9uKHVpbnQ2NCx1aW50NjQpdm9pZAovLwovLyBDcmVhdGUgdGhlIHJhZmZsZQovLwovLyBAcGFyYW0gdGlja2V0UHJpY2UgVGhlIHByaWNlIG9mIGEgc2luZ2xlIHRpY2tldCAodUFMR08pCi8vIEBwYXJhbSByYW5kb21uZXNzT3JhY2xlIFRoZSBhcHAgSUQgb2YgdGhlIHJhbmRvbW5lc3Mgb3JhY2xlCmFiaV9yb3V0ZV9jcmVhdGVBcHBsaWNhdGlvbjoKCS8vIHJhbmRvbW5lc3NPcmFjbGU6IHVpbnQ2NAoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMgoJYnRvaQoKCS8vIHRpY2tldFByaWNlOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBleGVjdXRlIGNyZWF0ZUFwcGxpY2F0aW9uKHVpbnQ2NCx1aW50NjQpdm9pZAoJY2FsbHN1YiBjcmVhdGVBcHBsaWNhdGlvbgoJaW50IDEKCXJldHVybgoKY3JlYXRlQXBwbGljYXRpb246Cglwcm90byAyIDAKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6NDMKCS8vIHRoaXMucmFuZG9tbmVzc09yYWNsZS52YWx1ZSA9IHJhbmRvbW5lc3NPcmFjbGUKCWJ5dGUgMHg3MjYxNmU2NDZmNmQ2ZTY1NzM3MzRmNzI2MTYzNmM2NSAvLyAicmFuZG9tbmVzc09yYWNsZSIKCWZyYW1lX2RpZyAtMiAvLyByYW5kb21uZXNzT3JhY2xlOiB1aW50NjQKCWFwcF9nbG9iYWxfcHV0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjQ0CgkvLyB0aGlzLnRpY2tldFByaWNlLnZhbHVlID0gdGlja2V0UHJpY2UKCWJ5dGUgMHg3NDY5NjM2YjY1NzQ1MDcyNjk2MzY1IC8vICJ0aWNrZXRQcmljZSIKCWZyYW1lX2RpZyAtMSAvLyB0aWNrZXRQcmljZTogdWludDY0CglhcHBfZ2xvYmFsX3B1dAoJcmV0c3ViCgovLyBzZXRBc3NldChhc3NldCl2b2lkCi8vCi8vIFNldCB0aGUgYXNzZXQgdG8gYmUgcmFmZmxlZAovLwovLyBAcGFyYW0gYXNzZXQgVGhlIGFzc2V0IHRvIGJlIHJhZmZsZWQKYWJpX3JvdXRlX3NldEFzc2V0OgoJLy8gYXNzZXQ6IGFzc2V0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgl0eG5hcyBBc3NldHMKCgkvLyBleGVjdXRlIHNldEFzc2V0KGFzc2V0KXZvaWQKCWNhbGxzdWIgc2V0QXNzZXQKCWludCAxCglyZXR1cm4KCnNldEFzc2V0OgoJcHJvdG8gMSAwCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjU0CgkvLyBhc3NlcnQoIXRoaXMuYXNzZXQuZXhpc3RzKQoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJYnl0ZSAweDYxNzM3MzY1NzQgLy8gImFzc2V0IgoJYXBwX2dsb2JhbF9nZXRfZXgKCXN3YXAKCXBvcAoJIQoJYXNzZXJ0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjU2CgkvLyBzZW5kQXNzZXRUcmFuc2Zlcih7CgkvLyAgICAgICBhc3NldFJlY2VpdmVyOiB0aGlzLmFwcC5hZGRyZXNzLAoJLy8gICAgICAgeGZlckFzc2V0OiBhc3NldCwKCS8vICAgICAgIGFzc2V0QW1vdW50OiAwLAoJLy8gICAgICAgZmVlOiAwLAoJLy8gICAgIH0pCglpdHhuX2JlZ2luCglpbnQgYXhmZXIKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6NTcKCS8vIGFzc2V0UmVjZWl2ZXI6IHRoaXMuYXBwLmFkZHJlc3MKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCglpdHhuX2ZpZWxkIEFzc2V0UmVjZWl2ZXIKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6NTgKCS8vIHhmZXJBc3NldDogYXNzZXQKCWZyYW1lX2RpZyAtMSAvLyBhc3NldDogYXNzZXQKCWl0eG5fZmllbGQgWGZlckFzc2V0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjU5CgkvLyBhc3NldEFtb3VudDogMAoJaW50IDAKCWl0eG5fZmllbGQgQXNzZXRBbW91bnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6NjAKCS8vIGZlZTogMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo2MwoJLy8gdGhpcy5hc3NldC52YWx1ZSA9IGFzc2V0CglieXRlIDB4NjE3MzczNjU3NCAvLyAiYXNzZXQiCglmcmFtZV9kaWcgLTEgLy8gYXNzZXQ6IGFzc2V0CglhcHBfZ2xvYmFsX3B1dAoJcmV0c3ViCgovLyBzdGFydFJhZmZsZSh1aW50NjQsdWludDY0LGF4ZmVyKXZvaWQKLy8KLy8gU3RhcnQgdGhlIHJhZmZsZQovLwovLyBAcGFyYW0gZW5kIFRoZSByb3VuZCBudW1iZXIgd2hlbiB0aGUgcmFmZmxlIGVuZHMKLy8gQHBhcmFtIGRyYXcgVGhlIHJvdW5kIG51bWJlciB3aGVuIHRoZSByYWZmbGUgaXMgZHJhd24KYWJpX3JvdXRlX3N0YXJ0UmFmZmxlOgoJLy8gZHJhdzogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglidG9pCgoJLy8gZW5kOiB1aW50NjQKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCgkvLyBheGZlcjogYXhmZXIKCXR4biBHcm91cEluZGV4CglpbnQgMQoJLQoJZHVwCglndHhucyBUeXBlRW51bQoJaW50IGF4ZmVyCgk9PQoJYXNzZXJ0CgoJLy8gZXhlY3V0ZSBzdGFydFJhZmZsZSh1aW50NjQsdWludDY0LGF4ZmVyKXZvaWQKCWNhbGxzdWIgc3RhcnRSYWZmbGUKCWludCAxCglyZXR1cm4KCnN0YXJ0UmFmZmxlOgoJcHJvdG8gMyAwCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjc0CgkvLyB2ZXJpZnlUeG4oYXhmZXIsIHsKCS8vICAgICAgIGFzc2V0QW1vdW50OiB7IGdyZWF0ZXJUaGFuOiAwIH0sCgkvLyAgICAgICBhc3NldFJlY2VpdmVyOiB0aGlzLmFwcC5hZGRyZXNzLAoJLy8gICAgICAgeGZlckFzc2V0OiB0aGlzLmFzc2V0LnZhbHVlLAoJLy8gICAgIH0pCgkvLyB2ZXJpZnkgYXNzZXRBbW91bnQKCWZyYW1lX2RpZyAtMSAvLyBheGZlcjogYXhmZXIKCWd0eG5zIEFzc2V0QW1vdW50CglpbnQgMAoJPgoJYXNzZXJ0CgoJLy8gdmVyaWZ5IGFzc2V0UmVjZWl2ZXIKCWZyYW1lX2RpZyAtMSAvLyBheGZlcjogYXhmZXIKCWd0eG5zIEFzc2V0UmVjZWl2ZXIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCgk9PQoJYXNzZXJ0CgoJLy8gdmVyaWZ5IHhmZXJBc3NldAoJZnJhbWVfZGlnIC0xIC8vIGF4ZmVyOiBheGZlcgoJZ3R4bnMgWGZlckFzc2V0CglieXRlIDB4NjE3MzczNjU3NCAvLyAiYXNzZXQiCglhcHBfZ2xvYmFsX2dldAoJPT0KCWFzc2VydAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo4MAoJLy8gYXNzZXJ0KGRyYXcgPiBlbmQpCglmcmFtZV9kaWcgLTMgLy8gZHJhdzogdWludDY0CglmcmFtZV9kaWcgLTIgLy8gZW5kOiB1aW50NjQKCT4KCWFzc2VydAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo4MQoJLy8gdGhpcy5lbmRSb3VuZC52YWx1ZSA9IGVuZAoJYnl0ZSAweDY1NmU2NDUyNmY3NTZlNjQgLy8gImVuZFJvdW5kIgoJZnJhbWVfZGlnIC0yIC8vIGVuZDogdWludDY0CglhcHBfZ2xvYmFsX3B1dAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo4MgoJLy8gdGhpcy5kcmF3Um91bmQudmFsdWUgPSBkcmF3CglieXRlIDB4NjQ3MjYxNzc1MjZmNzU2ZTY0IC8vICJkcmF3Um91bmQiCglmcmFtZV9kaWcgLTMgLy8gZHJhdzogdWludDY0CglhcHBfZ2xvYmFsX3B1dAoJcmV0c3ViCgovLyBidXlUaWNrZXRzKHVpbnQ2NCxwYXkpdm9pZAovLwovLyBCdXkgdGlja2V0cy4gTm90ZSB0aGlzIGNhbiBvbmx5IGJlIGNhbGxlZCBvbmNlIQovLyBJdCB3b3VsZCBiZSBwb3NzaWJsZSB0byBhbGxvdyBtdWx0aXBsZSBwdXJjaGFzZXMsIGJ1dAovLyBmb3Igc2ltcGxpY2l0eSwgb25seSBvbmUgcHVyY2hhc2UgaXMgYWxsb3dlZC4KLy8KLy8gQHBhcmFtIHBheW1lbnQgVGhlIHBheW1lbnQgZm9yIHRoZSB0aWNrZXRzCi8vIEBwYXJhbSBxdWFuaXR5IFRoZSBudW1iZXIgb2YgdGlja2V0cyB0byBidXkKLy8KLy8gQHJldHVybnMgVGhlIHRvdGFsIG51bWJlciBvZiB0aWNrZXRzIG93bmVkIGJ5IHRoZSBzZW5kZXIKYWJpX3JvdXRlX2J1eVRpY2tldHM6CgkvLyBxdWFudGl0eTogdWludDY0Cgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgoJLy8gcGF5bWVudDogcGF5Cgl0eG4gR3JvdXBJbmRleAoJaW50IDEKCS0KCWR1cAoJZ3R4bnMgVHlwZUVudW0KCWludCBwYXkKCT09Cglhc3NlcnQKCgkvLyBleGVjdXRlIGJ1eVRpY2tldHModWludDY0LHBheSl2b2lkCgljYWxsc3ViIGJ1eVRpY2tldHMKCWludCAxCglyZXR1cm4KCmJ1eVRpY2tldHM6Cglwcm90byAyIDA7IGJ5dGUgMHg7IGR1cG4gMwoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo5NgoJLy8gYXNzZXJ0KGdsb2JhbHMucm91bmQgPCB0aGlzLmVuZFJvdW5kLnZhbHVlKQoJZ2xvYmFsIFJvdW5kCglieXRlIDB4NjU2ZTY0NTI2Zjc1NmU2NCAvLyAiZW5kUm91bmQiCglhcHBfZ2xvYmFsX2dldAoJPAoJYXNzZXJ0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjk3CgkvLyBhc3NlcnQocXVhbnRpdHkgPiAwKQoJZnJhbWVfZGlnIC0yIC8vIHF1YW50aXR5OiB1aW50NjQKCWludCAwCgk+Cglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6OTkKCS8vIGFzc2VydCghdGhpcy50aWNrZXRzKHBheW1lbnQuc2VuZGVyKS5leGlzdHMpCglmcmFtZV9kaWcgLTEgLy8gcGF5bWVudDogcGF5CglndHhucyBTZW5kZXIKCWJveF9sZW4KCXN3YXAKCXBvcAoJIQoJYXNzZXJ0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEwMQoJLy8gbmV3VG90YWwgPSB0aGlzLnRvdGFsVGlja2V0cy52YWx1ZSArIHF1YW50aXR5ICsgMQoJYnl0ZSAweDc0NmY3NDYxNmM1NDY5NjM2YjY1NzQ3MyAvLyAidG90YWxUaWNrZXRzIgoJYXBwX2dsb2JhbF9nZXQKCWZyYW1lX2RpZyAtMiAvLyBxdWFudGl0eTogdWludDY0CgkrCglpbnQgMQoJKwoJZnJhbWVfYnVyeSAxIC8vIG5ld1RvdGFsOiB1aW50NjQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTAzCgkvLyBwcmVNQlIgPSB0aGlzLmFwcC5hZGRyZXNzLm1pbkJhbGFuY2UKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCglhY2N0X3BhcmFtc19nZXQgQWNjdE1pbkJhbGFuY2UKCWFzc2VydAoJZnJhbWVfYnVyeSAyIC8vIHByZU1CUjogdWludDY0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEwNAoJLy8gdGhpcy50aWNrZXRzKHBheW1lbnQuc2VuZGVyKS52YWx1ZSA9IHsgc3RhcnQ6IHRoaXMudG90YWxUaWNrZXRzLnZhbHVlLCBlbmQ6IG5ld1RvdGFsIC0gMSB9CglmcmFtZV9kaWcgLTEgLy8gcGF5bWVudDogcGF5CglndHhucyBTZW5kZXIKCWJ5dGUgMHg3NDZmNzQ2MTZjNTQ2OTYzNmI2NTc0NzMgLy8gInRvdGFsVGlja2V0cyIKCWFwcF9nbG9iYWxfZ2V0CglpdG9iCglmcmFtZV9kaWcgMSAvLyBuZXdUb3RhbDogdWludDY0CglpbnQgMQoJLQoJaXRvYgoJY29uY2F0Cglib3hfcHV0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEwNQoJLy8gbWJyRGVsdGEgPSB0aGlzLmFwcC5hZGRyZXNzLm1pbkJhbGFuY2UgLSBwcmVNQlIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCglhY2N0X3BhcmFtc19nZXQgQWNjdE1pbkJhbGFuY2UKCWFzc2VydAoJZnJhbWVfZGlnIDIgLy8gcHJlTUJSOiB1aW50NjQKCS0KCWZyYW1lX2J1cnkgMyAvLyBtYnJEZWx0YTogdWludDY0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEwNwoJLy8gdmVyaWZ5VHhuKHBheW1lbnQsIHsKCS8vICAgICAgIGFtb3VudDogdGhpcy50aWNrZXRQcmljZS52YWx1ZSAqIHF1YW50aXR5ICsgbWJyRGVsdGEsCgkvLyAgICAgICBzZW5kZXI6IHRoaXMudHhuLnNlbmRlciwKCS8vICAgICAgIHJlY2VpdmVyOiB0aGlzLmFwcC5hZGRyZXNzLAoJLy8gICAgIH0pCgkvLyB2ZXJpZnkgYW1vdW50CglmcmFtZV9kaWcgLTEgLy8gcGF5bWVudDogcGF5CglndHhucyBBbW91bnQKCWJ5dGUgMHg3NDY5NjM2YjY1NzQ1MDcyNjk2MzY1IC8vICJ0aWNrZXRQcmljZSIKCWFwcF9nbG9iYWxfZ2V0CglmcmFtZV9kaWcgLTIgLy8gcXVhbnRpdHk6IHVpbnQ2NAoJKgoJZnJhbWVfZGlnIDMgLy8gbWJyRGVsdGE6IHVpbnQ2NAoJKwoJPT0KCWFzc2VydAoKCS8vIHZlcmlmeSBzZW5kZXIKCWZyYW1lX2RpZyAtMSAvLyBwYXltZW50OiBwYXkKCWd0eG5zIFNlbmRlcgoJdHhuIFNlbmRlcgoJPT0KCWFzc2VydAoKCS8vIHZlcmlmeSByZWNlaXZlcgoJZnJhbWVfZGlnIC0xIC8vIHBheW1lbnQ6IHBheQoJZ3R4bnMgUmVjZWl2ZXIKCWdsb2JhbCBDdXJyZW50QXBwbGljYXRpb25BZGRyZXNzCgk9PQoJYXNzZXJ0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjExMwoJLy8gdGhpcy50b3RhbFRpY2tldHMudmFsdWUgPSBuZXdUb3RhbAoJYnl0ZSAweDc0NmY3NDYxNmM1NDY5NjM2YjY1NzQ3MyAvLyAidG90YWxUaWNrZXRzIgoJZnJhbWVfZGlnIDEgLy8gbmV3VG90YWw6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCXJldHN1YgoKZ2V0UmFuZG9tQnl0ZXM6Cglwcm90byAwIDAKCgkvLyBpZjBfY29uZGl0aW9uCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTE4CgkvLyB0aGlzLnJhbmRvbUJ5dGVzLmV4aXN0cwoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJYnl0ZSAweDcyNjE2ZTY0NmY2ZDQyNzk3NDY1NzMgLy8gInJhbmRvbUJ5dGVzIgoJYXBwX2dsb2JhbF9nZXRfZXgKCXN3YXAKCXBvcAoJYnogaWYwX2Vsc2UKCgkvLyBpZjBfY29uc2VxdWVudAoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjExOQoJLy8gdGhpcy5yYW5kb21CeXRlcy52YWx1ZSA9IHNoYTI1Nih0aGlzLnJhbmRvbUJ5dGVzLnZhbHVlKSBhcyBieXRlcwoJYnl0ZSAweDcyNjE2ZTY0NmY2ZDQyNzk3NDY1NzMgLy8gInJhbmRvbUJ5dGVzIgoJYnl0ZSAweDcyNjE2ZTY0NmY2ZDQyNzk3NDY1NzMgLy8gInJhbmRvbUJ5dGVzIgoJYXBwX2dsb2JhbF9nZXQKCXNoYTI1NgoJYXBwX2dsb2JhbF9wdXQKCWIgaWYwX2VuZAoKaWYwX2Vsc2U6CgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTIxCgkvLyB0aGlzLnJhbmRvbUJ5dGVzLnZhbHVlID0gc2VuZE1ldGhvZENhbGw8W3VpbnQ2NCwgYnl0ZXNdLCBieXRlcz4oewoJLy8gICAgICAgICBuYW1lOiAnbXVzdF9nZXQnLAoJLy8gICAgICAgICBtZXRob2RBcmdzOiBbdGhpcy5kcmF3Um91bmQudmFsdWUsICcnXSwKCS8vICAgICAgICAgYXBwbGljYXRpb25JRDogQXBwbGljYXRpb24uZnJvbUlEKHRoaXMucmFuZG9tbmVzc09yYWNsZS52YWx1ZSksCgkvLyAgICAgICAgIGZlZTogMCwKCS8vICAgICAgICAgb25Db21wbGV0aW9uOiBPbkNvbXBsZXRpb24uTm9PcCwKCS8vICAgICAgIH0pCglieXRlIDB4NzI2MTZlNjQ2ZjZkNDI3OTc0NjU3MyAvLyAicmFuZG9tQnl0ZXMiCglpdHhuX2JlZ2luCglpbnQgYXBwbAoJaXR4bl9maWVsZCBUeXBlRW51bQoJbWV0aG9kICJtdXN0X2dldCh1aW50NjQsYnl0ZVtdKWJ5dGVbXSIKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEyMwoJLy8gbWV0aG9kQXJnczogW3RoaXMuZHJhd1JvdW5kLnZhbHVlLCAnJ10KCWJ5dGUgMHg2NDcyNjE3NzUyNmY3NTZlNjQgLy8gImRyYXdSb3VuZCIKCWFwcF9nbG9iYWxfZ2V0CglpdG9iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoJYnl0ZSAweDAwMDAKCWl0eG5fZmllbGQgQXBwbGljYXRpb25BcmdzCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEyNAoJLy8gYXBwbGljYXRpb25JRDogQXBwbGljYXRpb24uZnJvbUlEKHRoaXMucmFuZG9tbmVzc09yYWNsZS52YWx1ZSkKCWJ5dGUgMHg3MjYxNmU2NDZmNmQ2ZTY1NzM3MzRmNzI2MTYzNmM2NSAvLyAicmFuZG9tbmVzc09yYWNsZSIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uSUQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTI1CgkvLyBmZWU6IDAKCWludCAwCglpdHhuX2ZpZWxkIEZlZQoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxMjYKCS8vIG9uQ29tcGxldGlvbjogT25Db21wbGV0aW9uLk5vT3AKCWludCAwIC8vIE5vT3AKCWl0eG5fZmllbGQgT25Db21wbGV0aW9uCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJaXR4biBOdW1Mb2dzCglpbnQgMQoJLQoJaXR4bmFzIExvZ3MKCWV4dHJhY3QgNCAwCglhcHBfZ2xvYmFsX3B1dAoKaWYwX2VuZDoKCXJldHN1YgoKLy8gZHJhdyhhcHBsaWNhdGlvbilib29sCi8vCi8vIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bnVzZWQtdmFycwphYmlfcm91dGVfZHJhdzoKCS8vIF9vcmFjbGVSZWZlcmVuY2U6IGFwcGxpY2F0aW9uCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgl0eG5hcyBBcHBsaWNhdGlvbnMKCgkvLyBleGVjdXRlIGRyYXcoYXBwbGljYXRpb24pYm9vbAoJY2FsbHN1YiBkcmF3CglpbnQgMQoJcmV0dXJuCgpkcmF3OgoJcHJvdG8gMSAwOyBieXRlIDB4OyBkdXBuIDQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTM1CgkvLyBhc3NlcnQoIXRoaXMud2lubmluZ1RpY2tldC5leGlzdHMpCgl0eG5hIEFwcGxpY2F0aW9ucyAwCglieXRlIDB4Nzc2OTZlNmU2OTZlNjc1NDY5NjM2YjY1NzQgLy8gIndpbm5pbmdUaWNrZXQiCglhcHBfZ2xvYmFsX2dldF9leAoJc3dhcAoJcG9wCgkhCglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTM2CgkvLyB0aGlzLmdldFJhbmRvbUJ5dGVzKCkKCWNhbGxzdWIgZ2V0UmFuZG9tQnl0ZXMKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTQwCgkvLyBuID0gdGhpcy50b3RhbFRpY2tldHMudmFsdWUKCWJ5dGUgMHg3NDZmNzQ2MTZjNTQ2OTYzNmI2NTc0NzMgLy8gInRvdGFsVGlja2V0cyIKCWFwcF9nbG9iYWxfZ2V0CglmcmFtZV9idXJ5IDEgLy8gbjogdWludDY0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE0MgoJLy8gb2Zmc2V0ID0gMAoJaW50IDAKCWZyYW1lX2J1cnkgMyAvLyBvZmZzZXQ6IHVpbnQ2NAoKZG9fd2hpbGVfMDoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxNDYKCS8vIHggPSBleHRyYWN0X3VpbnQ2NCh0aGlzLnJhbmRvbUJ5dGVzLnZhbHVlLCBvZmZzZXQpCglieXRlIDB4NzI2MTZlNjQ2ZjZkNDI3OTc0NjU3MyAvLyAicmFuZG9tQnl0ZXMiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIDMgLy8gb2Zmc2V0OiB1aW50NjQKCWV4dHJhY3RfdWludDY0CglmcmFtZV9idXJ5IDIgLy8geDogdWludDY0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE0OAoJLy8gb2Zmc2V0ID0gb2Zmc2V0ICsgOAoJZnJhbWVfZGlnIDMgLy8gb2Zmc2V0OiB1aW50NjQKCWludCA4CgkrCglmcmFtZV9idXJ5IDMgLy8gb2Zmc2V0OiB1aW50NjQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTUwCgkvLyBtYXhDb25kaXRpb24gPSB4ID4gUkFORF9NQVggLSAoKChSQU5EX01BWCAlIG4pICsgMSkgJSBuKQoJZnJhbWVfZGlnIDIgLy8geDogdWludDY0CglpbnQgMThfNDQ2Xzc0NF8wNzNfNzA5XzU1MV82MTUKCWludCAxOF80NDZfNzQ0XzA3M183MDlfNTUxXzYxNQoJZnJhbWVfZGlnIDEgLy8gbjogdWludDY0CgklCglpbnQgMQoJKwoJZnJhbWVfZGlnIDEgLy8gbjogdWludDY0CgklCgktCgk+CglmcmFtZV9idXJ5IDQgLy8gbWF4Q29uZGl0aW9uOiBib29sCglmcmFtZV9kaWcgNCAvLyBtYXhDb25kaXRpb246IGJvb2wKCWR1cAoJYnogc2tpcF9hbmQwCglmcmFtZV9kaWcgMyAvLyBvZmZzZXQ6IHVpbnQ2NAoJaW50IDMyCgk8CgkmJgoKc2tpcF9hbmQwOgoJYm56IGRvX3doaWxlXzAKCgkvLyBpZjFfY29uZGl0aW9uCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTUzCgkvLyBtYXhDb25kaXRpb24KCWZyYW1lX2RpZyA0IC8vIG1heENvbmRpdGlvbjogYm9vbAoJYnogaWYxX2VuZAoKCS8vIGlmMV9jb25zZXF1ZW50CgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTUzCgkvLyByZXR1cm4gZmFsc2U7CglpbnQgMAoJYnl0ZSAweDAwCglpbnQgMAoJdW5jb3ZlciAyCglzZXRiaXQKCWJ5dGUgMHgxNTFmN2M3NQoJc3dhcAoJY29uY2F0Cglsb2cKCXJldHN1YgoKaWYxX2VuZDoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxNTUKCS8vIHRoaXMud2lubmluZ1RpY2tldC52YWx1ZSA9IHggJSBuCglieXRlIDB4Nzc2OTZlNmU2OTZlNjc1NDY5NjM2YjY1NzQgLy8gIndpbm5pbmdUaWNrZXQiCglmcmFtZV9kaWcgMiAvLyB4OiB1aW50NjQKCWZyYW1lX2RpZyAxIC8vIG46IHVpbnQ2NAoJJQoJYXBwX2dsb2JhbF9wdXQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTU2CgkvLyByZXR1cm4gdHJ1ZTsKCWludCAxCglieXRlIDB4MDAKCWludCAwCgl1bmNvdmVyIDIKCXNldGJpdAoJYnl0ZSAweDE1MWY3Yzc1Cglzd2FwCgljb25jYXQKCWxvZwoJcmV0c3ViCgovLyBjbGFpbSgpdm9pZAovLwovLyBTZW5kIHRoZSBhc3NldCB0byB0aGUgdGhlIHNlbmRlciBpZiB0aGV5IGhhdmUgdGhlIHdpbm5pbmcgdGlja2V0CmFiaV9yb3V0ZV9jbGFpbToKCS8vIGV4ZWN1dGUgY2xhaW0oKXZvaWQKCWNhbGxzdWIgY2xhaW0KCWludCAxCglyZXR1cm4KCmNsYWltOgoJcHJvdG8gMCAwOyBieXRlIDB4OyBkdXBuIDEKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTYxCgkvLyB0aWNrZXRSYW5nZSA9IHRoaXMudGlja2V0cyh0aGlzLnR4bi5zZW5kZXIpLnZhbHVlCgl0eG4gU2VuZGVyCglmcmFtZV9idXJ5IDEgLy8gc3RvcmFnZSBrZXkvL3RpY2tldFJhbmdlCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE2MwoJLy8gYXNzZXJ0KHRpY2tldFJhbmdlLnN0YXJ0IDw9IHRoaXMud2lubmluZ1RpY2tldC52YWx1ZSkKCWZyYW1lX2RpZyAxIC8vIHN0b3JhZ2Uga2V5Ly90aWNrZXRSYW5nZQoJYm94X2dldAoJYXNzZXJ0CglleHRyYWN0IDAgOAoJYnRvaQoJYnl0ZSAweDc3Njk2ZTZlNjk2ZTY3NTQ2OTYzNmI2NTc0IC8vICJ3aW5uaW5nVGlja2V0IgoJYXBwX2dsb2JhbF9nZXQKCTw9Cglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTY0CgkvLyBhc3NlcnQodGlja2V0UmFuZ2UuZW5kID49IHRoaXMud2lubmluZ1RpY2tldC52YWx1ZSkKCWZyYW1lX2RpZyAxIC8vIHN0b3JhZ2Uga2V5Ly90aWNrZXRSYW5nZQoJYm94X2dldAoJYXNzZXJ0CglleHRyYWN0IDggOAoJYnRvaQoJYnl0ZSAweDc3Njk2ZTZlNjk2ZTY3NTQ2OTYzNmI2NTc0IC8vICJ3aW5uaW5nVGlja2V0IgoJYXBwX2dsb2JhbF9nZXQKCT49Cglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTY2CgkvLyBzZW5kQXNzZXRUcmFuc2Zlcih7CgkvLyAgICAgICBhc3NldFJlY2VpdmVyOiB0aGlzLnR4bi5zZW5kZXIsCgkvLyAgICAgICB4ZmVyQXNzZXQ6IHRoaXMuYXNzZXQudmFsdWUsCgkvLyAgICAgICBhc3NldEFtb3VudDogdGhpcy5hcHAuYWRkcmVzcy5hc3NldEJhbGFuY2UodGhpcy5hc3NldC52YWx1ZSksCgkvLyAgICAgICBhc3NldENsb3NlVG86IHRoaXMudHhuLnNlbmRlciwKCS8vICAgICAgIGZlZTogMCwKCS8vICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IGF4ZmVyCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE2NwoJLy8gYXNzZXRSZWNlaXZlcjogdGhpcy50eG4uc2VuZGVyCgl0eG4gU2VuZGVyCglpdHhuX2ZpZWxkIEFzc2V0UmVjZWl2ZXIKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTY4CgkvLyB4ZmVyQXNzZXQ6IHRoaXMuYXNzZXQudmFsdWUKCWJ5dGUgMHg2MTczNzM2NTc0IC8vICJhc3NldCIKCWFwcF9nbG9iYWxfZ2V0CglpdHhuX2ZpZWxkIFhmZXJBc3NldAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxNjkKCS8vIGFzc2V0QW1vdW50OiB0aGlzLmFwcC5hZGRyZXNzLmFzc2V0QmFsYW5jZSh0aGlzLmFzc2V0LnZhbHVlKQoJZ2xvYmFsIEN1cnJlbnRBcHBsaWNhdGlvbkFkZHJlc3MKCWJ5dGUgMHg2MTczNzM2NTc0IC8vICJhc3NldCIKCWFwcF9nbG9iYWxfZ2V0Cglhc3NldF9ob2xkaW5nX2dldCBBc3NldEJhbGFuY2UKCWFzc2VydAoJaXR4bl9maWVsZCBBc3NldEFtb3VudAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxNzAKCS8vIGFzc2V0Q2xvc2VUbzogdGhpcy50eG4uc2VuZGVyCgl0eG4gU2VuZGVyCglpdHhuX2ZpZWxkIEFzc2V0Q2xvc2VUbwoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxNzEKCS8vIGZlZTogMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gU3VibWl0IGlubmVyIHRyYW5zYWN0aW9uCglpdHhuX3N1Ym1pdAoJcmV0c3ViCgovLyBnZXRSZWZ1bmQoKXZvaWQKLy8KLy8gQWxsb3dzIHB1cmNoYXNlcnMgdG8gZ2V0IGEgcmVmdW5kIGlmIHRoZSB3aW5uaW5nIHRpY2tldCBoYXMgbm90IGJlZW4gZHJhd24KLy8gYW5kIDE1MTIgcm91bmRzIGhhdmUgcGFzc2VkIHNpbmNlIHRoZSBkcmF3IHJvdW5kLCBtZWFuaW5nIHRoZSBvcmFjbGUgbm8KLy8gbG9uZ2VyIGhhcyB0aGUgZGF0YSBmb3IgdGhlIGRyYXcgcm91bmQKYWJpX3JvdXRlX2dldFJlZnVuZDoKCS8vIGV4ZWN1dGUgZ2V0UmVmdW5kKCl2b2lkCgljYWxsc3ViIGdldFJlZnVuZAoJaW50IDEKCXJldHVybgoKZ2V0UmVmdW5kOgoJcHJvdG8gMCAwOyBieXRlIDB4OyBkdXBuIDIKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTgxCgkvLyBhc3NlcnQoIXRoaXMud2lubmluZ1RpY2tldC5leGlzdHMpCgl0eG5hIEFwcGxpY2F0aW9ucyAwCglieXRlIDB4Nzc2OTZlNmU2OTZlNjc1NDY5NjM2YjY1NzQgLy8gIndpbm5pbmdUaWNrZXQiCglhcHBfZ2xvYmFsX2dldF9leAoJc3dhcAoJcG9wCgkhCglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTgyCgkvLyBhc3NlcnQoZ2xvYmFscy5yb3VuZCA+IHRoaXMuZHJhd1JvdW5kLnZhbHVlICsgMTUxMikKCWdsb2JhbCBSb3VuZAoJYnl0ZSAweDY0NzI2MTc3NTI2Zjc1NmU2NCAvLyAiZHJhd1JvdW5kIgoJYXBwX2dsb2JhbF9nZXQKCWludCAxNTEyCgkrCgk+Cglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTg0CgkvLyB0aWNrZXRSYW5nZSA9IHRoaXMudGlja2V0cyh0aGlzLnR4bi5zZW5kZXIpLnZhbHVlCgl0eG4gU2VuZGVyCglmcmFtZV9idXJ5IDEgLy8gc3RvcmFnZSBrZXkvL3RpY2tldFJhbmdlCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE4NQoJLy8gdGlja2V0Q291bnQgPSB0aWNrZXRSYW5nZS5lbmQgLSB0aWNrZXRSYW5nZS5zdGFydCArIDEKCWZyYW1lX2RpZyAxIC8vIHN0b3JhZ2Uga2V5Ly90aWNrZXRSYW5nZQoJYm94X2dldAoJYXNzZXJ0CglleHRyYWN0IDggOAoJYnRvaQoJZnJhbWVfZGlnIDEgLy8gc3RvcmFnZSBrZXkvL3RpY2tldFJhbmdlCglib3hfZ2V0Cglhc3NlcnQKCWV4dHJhY3QgMCA4CglidG9pCgktCglpbnQgMQoJKwoJZnJhbWVfYnVyeSAyIC8vIHRpY2tldENvdW50OiB1aW50NjQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTg3CgkvLyB0aGlzLnRpY2tldHModGhpcy50eG4uc2VuZGVyKS5kZWxldGUoKQoJdHhuIFNlbmRlcgoJYm94X2RlbAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxODkKCS8vIHNlbmRQYXltZW50KHsKCS8vICAgICAgIGFtb3VudDogdGhpcy50aWNrZXRQcmljZS52YWx1ZSAqIHRpY2tldENvdW50LAoJLy8gICAgICAgcmVjZWl2ZXI6IHRoaXMudHhuLnNlbmRlciwKCS8vICAgICAgIGZlZTogMCwKCS8vICAgICB9KQoJaXR4bl9iZWdpbgoJaW50IHBheQoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxOTAKCS8vIGFtb3VudDogdGhpcy50aWNrZXRQcmljZS52YWx1ZSAqIHRpY2tldENvdW50CglieXRlIDB4NzQ2OTYzNmI2NTc0NTA3MjY5NjM2NSAvLyAidGlja2V0UHJpY2UiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIDIgLy8gdGlja2V0Q291bnQ6IHVpbnQ2NAoJKgoJaXR4bl9maWVsZCBBbW91bnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTkxCgkvLyByZWNlaXZlcjogdGhpcy50eG4uc2VuZGVyCgl0eG4gU2VuZGVyCglpdHhuX2ZpZWxkIFJlY2VpdmVyCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE5MgoJLy8gZmVlOiAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCgkvLyBTdWJtaXQgaW5uZXIgdHJhbnNhY3Rpb24KCWl0eG5fc3VibWl0CglyZXRzdWIKCmNyZWF0ZV9Ob09wOgoJbWV0aG9kICJjcmVhdGVBcHBsaWNhdGlvbih1aW50NjQsdWludDY0KXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCBhYmlfcm91dGVfY3JlYXRlQXBwbGljYXRpb24KCWVycgoKY2FsbF9Ob09wOgoJbWV0aG9kICJzZXRBc3NldChhc3NldCl2b2lkIgoJbWV0aG9kICJzdGFydFJhZmZsZShheGZlcix1aW50NjQsdWludDY0KXZvaWQiCgltZXRob2QgImJ1eVRpY2tldHMocGF5LHVpbnQ2NCl2b2lkIgoJbWV0aG9kICJkcmF3KGFwcGxpY2F0aW9uKWJvb2wiCgltZXRob2QgImNsYWltKCl2b2lkIgoJbWV0aG9kICJnZXRSZWZ1bmQoKXZvaWQiCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAwCgltYXRjaCBhYmlfcm91dGVfc2V0QXNzZXQgYWJpX3JvdXRlX3N0YXJ0UmFmZmxlIGFiaV9yb3V0ZV9idXlUaWNrZXRzIGFiaV9yb3V0ZV9kcmF3IGFiaV9yb3V0ZV9jbGFpbSBhYmlfcm91dGVfZ2V0UmVmdW5kCgllcnI=", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDk=" + }, + "contract": { + "name": "NFTRaffle", + "desc": "", + "methods": [ + { + "name": "createApplication", + "args": [ + { + "name": "ticketPrice", + "type": "uint64", + "desc": "The price of a single ticket (uALGO)" + }, + { + "name": "randomnessOracle", + "type": "uint64", + "desc": "The app ID of the randomness oracle" + } + ], + "desc": "Create the raffle", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "setAsset", + "args": [ + { + "name": "asset", + "type": "asset", + "desc": "The asset to be raffled" + } + ], + "desc": "Set the asset to be raffled", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "startRaffle", + "args": [ + { + "name": "axfer", + "type": "axfer", + "desc": "" + }, + { + "name": "end", + "type": "uint64", + "desc": "The round number when the raffle ends" + }, + { + "name": "draw", + "type": "uint64", + "desc": "The round number when the raffle is drawn" + } + ], + "desc": "Start the raffle", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "buyTickets", + "args": [ + { + "name": "payment", + "type": "pay", + "desc": "The payment for the tickets" + }, + { + "name": "quantity", + "type": "uint64", + "desc": "" + } + ], + "desc": "Buy tickets. Note this can only be called once!It would be possible to allow multiple purchases, butfor simplicity, only one purchase is allowed.", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "draw", + "args": [ + { + "name": "_oracleReference", + "type": "application", + "desc": "" + } + ], + "desc": "", + "returns": { + "type": "bool", + "desc": "" + } + }, + { + "name": "claim", + "args": [], + "desc": "Send the asset to the the sender if they have the winning ticket", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "getRefund", + "args": [], + "desc": "Allows purchasers to get a refund if the winning ticket has not been drawnand 1512 rounds have passed since the draw round, meaning the oracle nolonger has the data for the draw round", + "returns": { + "type": "void", + "desc": "" + } + } + ] + } +} \ No newline at end of file diff --git a/examples/raffle/artifacts/NFTRaffle.arc4.json b/examples/raffle/artifacts/NFTRaffle.arc4.json new file mode 100644 index 000000000..773f52fad --- /dev/null +++ b/examples/raffle/artifacts/NFTRaffle.arc4.json @@ -0,0 +1,119 @@ +{ + "name": "NFTRaffle", + "desc": "", + "methods": [ + { + "name": "createApplication", + "args": [ + { + "name": "ticketPrice", + "type": "uint64", + "desc": "The price of a single ticket (uALGO)" + }, + { + "name": "randomnessOracle", + "type": "uint64", + "desc": "The app ID of the randomness oracle" + } + ], + "desc": "Create the raffle", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "setAsset", + "args": [ + { + "name": "asset", + "type": "asset", + "desc": "The asset to be raffled" + } + ], + "desc": "Set the asset to be raffled", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "startRaffle", + "args": [ + { + "name": "axfer", + "type": "axfer", + "desc": "" + }, + { + "name": "end", + "type": "uint64", + "desc": "The round number when the raffle ends" + }, + { + "name": "draw", + "type": "uint64", + "desc": "The round number when the raffle is drawn" + } + ], + "desc": "Start the raffle", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "buyTickets", + "args": [ + { + "name": "payment", + "type": "pay", + "desc": "The payment for the tickets" + }, + { + "name": "quantity", + "type": "uint64", + "desc": "" + } + ], + "desc": "Buy tickets. Note this can only be called once!It would be possible to allow multiple purchases, butfor simplicity, only one purchase is allowed.", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "draw", + "args": [ + { + "name": "_oracleReference", + "type": "application", + "desc": "" + } + ], + "desc": "", + "returns": { + "type": "bool", + "desc": "" + } + }, + { + "name": "claim", + "args": [], + "desc": "Send the asset to the the sender if they have the winning ticket", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "getRefund", + "args": [], + "desc": "Allows purchasers to get a refund if the winning ticket has not been drawnand 1512 rounds have passed since the draw round, meaning the oracle nolonger has the data for the draw round", + "returns": { + "type": "void", + "desc": "" + } + } + ] +} \ No newline at end of file diff --git a/examples/raffle/artifacts/NFTRaffle.clear.teal b/examples/raffle/artifacts/NFTRaffle.clear.teal new file mode 100644 index 000000000..858e5674c --- /dev/null +++ b/examples/raffle/artifacts/NFTRaffle.clear.teal @@ -0,0 +1 @@ +#pragma version 9 \ No newline at end of file diff --git a/examples/raffle/artifacts/NFTRaffle.json b/examples/raffle/artifacts/NFTRaffle.json new file mode 100644 index 000000000..5eacbbd4b --- /dev/null +++ b/examples/raffle/artifacts/NFTRaffle.json @@ -0,0 +1,207 @@ +{ + "hints": { + "createApplication(uint64,uint64)void": { + "call_config": { + "no_op": "CREATE" + } + }, + "setAsset(asset)void": { + "call_config": { + "no_op": "CALL" + } + }, + "startRaffle(uint64,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "buyTickets(pay,uint64)void": { + "call_config": { + "no_op": "CALL" + } + }, + "draw()void": { + "call_config": { + "no_op": "CALL" + } + }, + "claim()void": { + "call_config": { + "no_op": "CALL" + } + }, + "getRefund()void": { + "call_config": { + "no_op": "CALL" + } + } + }, + "bare_call_config": { + "no_op": "NEVER", + "opt_in": "NEVER", + "close_out": "NEVER", + "update_application": "NEVER", + "delete_application": "NEVER" + }, + "schema": { + "local": { + "declared": {}, + "reserved": {} + }, + "global": { + "declared": { + "randomnessOracle": { + "type": "uint64", + "key": "randomnessOracle" + }, + "ticketPrice": { + "type": "uint64", + "key": "ticketPrice" + }, + "asset": { + "type": "uint64", + "key": "asset" + }, + "endRound": { + "type": "uint64", + "key": "endRound" + }, + "drawRound": { + "type": "uint64", + "key": "drawRound" + }, + "totalTickets": { + "type": "uint64", + "key": "totalTickets" + }, + "winningTicket": { + "type": "uint64", + "key": "winningTicket" + } + }, + "reserved": {} + } + }, + "state": { + "global": { + "num_byte_slices": 0, + "num_uints": 7 + }, + "local": { + "num_byte_slices": 0, + "num_uints": 0 + } + }, + "source": { + "approval": "I3ByYWdtYSB2ZXJzaW9uIDkKCnR4biBBcHBsaWNhdGlvbklECmludCAwCj4KaW50IDYKKgp0eG4gT25Db21wbGV0aW9uCisKc3dpdGNoIGNyZWF0ZV9Ob09wIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgTk9UX0lNUExFTUVOVEVEIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgY2FsbF9Ob09wCgpOT1RfSU1QTEVNRU5URUQ6CgllcnIKCmFiaV9yb3V0ZV9jcmVhdGVBcHBsaWNhdGlvbjoKCS8vIG5vIGR1cG4gbmVlZGVkCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglidG9pCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgljYWxsc3ViIGNyZWF0ZUFwcGxpY2F0aW9uCglpbnQgMQoJcmV0dXJuCgpjcmVhdGVBcHBsaWNhdGlvbjoKCXByb3RvIDIgMAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czozOQoJLy8gdGhpcy5yYW5kb21uZXNzT3JhY2xlLnZhbHVlID0gcmFuZG9tbmVzc09yYWNsZQoJYnl0ZSAicmFuZG9tbmVzc09yYWNsZSIKCWZyYW1lX2RpZyAtMiAvLyByYW5kb21uZXNzT3JhY2xlOiB1aW50NjQKCWFwcF9nbG9iYWxfcHV0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjQwCgkvLyB0aGlzLnRpY2tldFByaWNlLnZhbHVlID0gdGlja2V0UHJpY2UKCWJ5dGUgInRpY2tldFByaWNlIgoJZnJhbWVfZGlnIC0xIC8vIHRpY2tldFByaWNlOiB1aW50NjQKCWFwcF9nbG9iYWxfcHV0CglyZXRzdWIKCmFiaV9yb3V0ZV9zZXRBc3NldDoKCS8vIG5vIGR1cG4gbmVlZGVkCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgl0eG5hcyBBc3NldHMKCWNhbGxzdWIgc2V0QXNzZXQKCWludCAxCglyZXR1cm4KCnNldEFzc2V0OgoJcHJvdG8gMSAwCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjUwCgkvLyBhc3NlcnQoIXRoaXMuYXNzZXQuZXhpc3RzKQoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJYnl0ZSAiYXNzZXQiCglhcHBfZ2xvYmFsX2dldF9leAoJc3dhcAoJcG9wCgkhCglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6NTIKCS8vIHNlbmRBc3NldFRyYW5zZmVyKHsKCWl0eG5fYmVnaW4KCWludCBheGZlcgoJaXR4bl9maWVsZCBUeXBlRW51bQoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo1MwoJLy8gYXNzZXRSZWNlaXZlcjogdGhpcy5hcHAuYWRkcmVzcwoJdHhuYSBBcHBsaWNhdGlvbnMgMAoJYXBwX3BhcmFtc19nZXQgQXBwQWRkcmVzcwoJYXNzZXJ0CglpdHhuX2ZpZWxkIEFzc2V0UmVjZWl2ZXIKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6NTQKCS8vIHhmZXJBc3NldDogYXNzZXQKCWZyYW1lX2RpZyAtMSAvLyBhc3NldDogYXNzZXQKCWl0eG5fZmllbGQgWGZlckFzc2V0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjU1CgkvLyBhc3NldEFtb3VudDogMAoJaW50IDAKCWl0eG5fZmllbGQgQXNzZXRBbW91bnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6NTYKCS8vIGZlZTogMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCglpdHhuX3N1Ym1pdAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo1OQoJLy8gdGhpcy5hc3NldC52YWx1ZSA9IGFzc2V0CglieXRlICJhc3NldCIKCWZyYW1lX2RpZyAtMSAvLyBhc3NldDogYXNzZXQKCWFwcF9nbG9iYWxfcHV0CglyZXRzdWIKCmFiaV9yb3V0ZV9zdGFydFJhZmZsZToKCS8vIG5vIGR1cG4gbmVlZGVkCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAyCglidG9pCgl0eG5hIEFwcGxpY2F0aW9uQXJncyAxCglidG9pCgljYWxsc3ViIHN0YXJ0UmFmZmxlCglpbnQgMQoJcmV0dXJuCgpzdGFydFJhZmZsZToKCXByb3RvIDIgMAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo3MAoJLy8gYXNzZXJ0KHRoaXMuYXBwLmFkZHJlc3MuYXNzZXRCYWxhbmNlKHRoaXMuYXNzZXQudmFsdWUpID4gMCkKCXR4bmEgQXBwbGljYXRpb25zIDAKCWFwcF9wYXJhbXNfZ2V0IEFwcEFkZHJlc3MKCWFzc2VydAoJYnl0ZSAiYXNzZXQiCglhcHBfZ2xvYmFsX2dldAoJYXNzZXRfaG9sZGluZ19nZXQgQXNzZXRCYWxhbmNlCglhc3NlcnQKCWludCAwCgk+Cglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6NzIKCS8vIGFzc2VydChkcmF3ID4gZW5kKQoJZnJhbWVfZGlnIC0yIC8vIGRyYXc6IHVpbnQ2NAoJZnJhbWVfZGlnIC0xIC8vIGVuZDogdWludDY0Cgk+Cglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6NzMKCS8vIHRoaXMuZW5kUm91bmQudmFsdWUgPSBlbmQKCWJ5dGUgImVuZFJvdW5kIgoJZnJhbWVfZGlnIC0xIC8vIGVuZDogdWludDY0CglhcHBfZ2xvYmFsX3B1dAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo3NAoJLy8gdGhpcy5kcmF3Um91bmQudmFsdWUgPSBkcmF3CglieXRlICJkcmF3Um91bmQiCglmcmFtZV9kaWcgLTIgLy8gZHJhdzogdWludDY0CglhcHBfZ2xvYmFsX3B1dAoJcmV0c3ViCgphYmlfcm91dGVfYnV5VGlja2V0czoKCWJ5dGUgMHgKCXR4bmEgQXBwbGljYXRpb25BcmdzIDEKCWJ0b2kKCXR4biBHcm91cEluZGV4CglpbnQgMQoJLQoJZHVwCglndHhucyBUeXBlRW51bQoJaW50IHBheQoJPT0KCWFzc2VydAoJY2FsbHN1YiBidXlUaWNrZXRzCglpbnQgMQoJcmV0dXJuCgpidXlUaWNrZXRzOgoJcHJvdG8gMyAwCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjg4CgkvLyBhc3NlcnQoZ2xvYmFscy5yb3VuZCA8IHRoaXMuZW5kUm91bmQudmFsdWUpCglnbG9iYWwgUm91bmQKCWJ5dGUgImVuZFJvdW5kIgoJYXBwX2dsb2JhbF9nZXQKCTwKCWFzc2VydAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo4OQoJLy8gYXNzZXJ0KHF1YW5pdHkgPiAwKQoJZnJhbWVfZGlnIC0yIC8vIHF1YW5pdHk6IHVpbnQ2NAoJaW50IDAKCT4KCWFzc2VydAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo5MQoJLy8gYXNzZXJ0KHBheW1lbnQuYW1vdW50ID09PSB0aGlzLnRpY2tldFByaWNlLnZhbHVlICogcXVhbml0eSkKCWZyYW1lX2RpZyAtMSAvLyBwYXltZW50OiBwYXkKCWd0eG5zIEFtb3VudAoJYnl0ZSAidGlja2V0UHJpY2UiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIC0yIC8vIHF1YW5pdHk6IHVpbnQ2NAoJKgoJPT0KCWFzc2VydAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo5MgoJLy8gYXNzZXJ0KHBheW1lbnQuc2VuZGVyID09PSB0aGlzLnR4bi5zZW5kZXIpCglmcmFtZV9kaWcgLTEgLy8gcGF5bWVudDogcGF5CglndHhucyBTZW5kZXIKCXR4biBTZW5kZXIKCT09Cglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6OTMKCS8vIGFzc2VydChwYXltZW50LnJlY2VpdmVyID09PSB0aGlzLmFwcC5hZGRyZXNzKQoJZnJhbWVfZGlnIC0xIC8vIHBheW1lbnQ6IHBheQoJZ3R4bnMgUmVjZWl2ZXIKCXR4bmEgQXBwbGljYXRpb25zIDAKCWFwcF9wYXJhbXNfZ2V0IEFwcEFkZHJlc3MKCWFzc2VydAoJPT0KCWFzc2VydAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czo5NQoJLy8gYXNzZXJ0KCF0aGlzLnRpY2tldHMocGF5bWVudC5zZW5kZXIpLmV4aXN0cykKCWZyYW1lX2RpZyAtMSAvLyBwYXltZW50OiBwYXkKCWd0eG5zIFNlbmRlcgoJYm94X2xlbgoJc3dhcAoJcG9wCgkhCglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6OTcKCS8vIG5ld1RvdGFsID0gdGhpcy50b3RhbFRpY2tldHMudmFsdWUgKyBxdWFuaXR5ICsgMQoJYnl0ZSAidG90YWxUaWNrZXRzIgoJYXBwX2dsb2JhbF9nZXQKCWZyYW1lX2RpZyAtMiAvLyBxdWFuaXR5OiB1aW50NjQKCSsKCWludCAxCgkrCglmcmFtZV9idXJ5IC0zIC8vIG5ld1RvdGFsOiB1aW50NjQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6OTkKCS8vIHRoaXMudGlja2V0cyhwYXltZW50LnNlbmRlcikudmFsdWUgPSB7IHN0YXJ0OiB0aGlzLnRvdGFsVGlja2V0cy52YWx1ZSwgZW5kOiBuZXdUb3RhbCAtIDEgfQoJZnJhbWVfZGlnIC0xIC8vIHBheW1lbnQ6IHBheQoJZ3R4bnMgU2VuZGVyCglieXRlICJ0b3RhbFRpY2tldHMiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJZnJhbWVfZGlnIC0zIC8vIG5ld1RvdGFsOiB1aW50NjQKCWludCAxCgktCglpdG9iCgljb25jYXQKCWJveF9wdXQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTAwCgkvLyB0aGlzLnRvdGFsVGlja2V0cy52YWx1ZSA9IG5ld1RvdGFsCglieXRlICJ0b3RhbFRpY2tldHMiCglmcmFtZV9kaWcgLTMgLy8gbmV3VG90YWw6IHVpbnQ2NAoJYXBwX2dsb2JhbF9wdXQKCXJldHN1YgoKYWJpX3JvdXRlX2RyYXc6CglieXRlIDB4CgljYWxsc3ViIGRyYXcKCWludCAxCglyZXR1cm4KCmRyYXc6Cglwcm90byAxIDAKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTA1CgkvLyBhc3NlcnQoIXRoaXMud2lubmluZ1RpY2tldC5leGlzdHMpCgl0eG5hIEFwcGxpY2F0aW9ucyAwCglieXRlICJ3aW5uaW5nVGlja2V0IgoJYXBwX2dsb2JhbF9nZXRfZXgKCXN3YXAKCXBvcAoJIQoJYXNzZXJ0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEwNwoJLy8gb3V0cHV0ID0gc2VuZE1ldGhvZENhbGw8W3VpbnQ2NCwgYnl0ZXNdLCBieXRlcz4oewoJaXR4bl9iZWdpbgoJaW50IGFwcGwKCWl0eG5fZmllbGQgVHlwZUVudW0KCW1ldGhvZCAibXVzdF9nZXQodWludDY0LGJ5dGVbXSlieXRlW10iCglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxMDkKCS8vIG1ldGhvZEFyZ3M6IFt0aGlzLmRyYXdSb3VuZC52YWx1ZSwgJyddCglieXRlICJkcmF3Um91bmQiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJaXR4bl9maWVsZCBBcHBsaWNhdGlvbkFyZ3MKCWJ5dGUgIiIKCWR1cAoJbGVuCglpdG9iCglleHRyYWN0IDYgMgoJc3dhcAoJY29uY2F0CglpdHhuX2ZpZWxkIEFwcGxpY2F0aW9uQXJncwoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxMTAKCS8vIGFwcGxpY2F0aW9uSUQ6IEFwcGxpY2F0aW9uLmZyb21JbmRleCh0aGlzLnJhbmRvbW5lc3NPcmFjbGUudmFsdWUpCglieXRlICJyYW5kb21uZXNzT3JhY2xlIgoJYXBwX2dsb2JhbF9nZXQKCWl0eG5fZmllbGQgQXBwbGljYXRpb25JRAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxMTEKCS8vIGZlZTogMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjExMgoJLy8gb25Db21wbGV0aW9uOiAnTm9PcCcKCWludCBOb09wCglpdHhuX2ZpZWxkIE9uQ29tcGxldGlvbgoJaXR4bl9zdWJtaXQKCWl0eG4gTnVtTG9ncwoJaW50IDEKCS0KCWl0eG5hcyBMb2dzCglleHRyYWN0IDQgMAoJZnJhbWVfYnVyeSAtMSAvLyBvdXRwdXQ6IGJ5dGVzCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjExOQoJLy8gdGhpcy53aW5uaW5nVGlja2V0LnZhbHVlID0gYnRvYmlnaW50KG91dHB1dCkgJSB0aGlzLnRvdGFsVGlja2V0cy52YWx1ZQoJYnl0ZSAid2lubmluZ1RpY2tldCIKCWZyYW1lX2RpZyAtMSAvLyBvdXRwdXQ6IGJ5dGVzCglieXRlICJ0b3RhbFRpY2tldHMiCglhcHBfZ2xvYmFsX2dldAoJaXRvYgoJYiUKCWJ0b2kKCWFwcF9nbG9iYWxfcHV0CglyZXRzdWIKCmFiaV9yb3V0ZV9jbGFpbToKCWJ5dGUgMHgKCWNhbGxzdWIgY2xhaW0KCWludCAxCglyZXR1cm4KCmNsYWltOgoJcHJvdG8gMSAwCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEyNAoJLy8gdGlja2V0UmFuZ2UgPSB0aGlzLnRpY2tldHModGhpcy50eG4uc2VuZGVyKS52YWx1ZQoJdHhuIFNlbmRlcgoJZnJhbWVfYnVyeSAtMSAvLyBzdG9yYWdlIGtleS8vdGlja2V0UmFuZ2UKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTI2CgkvLyBhc3NlcnQodGlja2V0UmFuZ2Uuc3RhcnQgPD0gdGhpcy53aW5uaW5nVGlja2V0LnZhbHVlKQoJZnJhbWVfZGlnIC0xIC8vIHN0b3JhZ2Uga2V5Ly90aWNrZXRSYW5nZQoJYm94X2dldAoJYXNzZXJ0CglzdG9yZSAwIC8vIGZ1bGwgYXJyYXkKCWludCAwIC8vIGluaXRpYWwgb2Zmc2V0CglpbnQgMCAvLyBoZWFkT2Zmc2V0CgkrCglsb2FkIDAgLy8gZnVsbCBhcnJheQoJc3dhcAoJaW50IDgKCWV4dHJhY3QzCglidG9pCglieXRlICJ3aW5uaW5nVGlja2V0IgoJYXBwX2dsb2JhbF9nZXQKCTw9Cglhc3NlcnQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTI3CgkvLyBhc3NlcnQodGlja2V0UmFuZ2UuZW5kID49IHRoaXMud2lubmluZ1RpY2tldC52YWx1ZSkKCWZyYW1lX2RpZyAtMSAvLyBzdG9yYWdlIGtleS8vdGlja2V0UmFuZ2UKCWJveF9nZXQKCWFzc2VydAoJc3RvcmUgMCAvLyBmdWxsIGFycmF5CglpbnQgMCAvLyBpbml0aWFsIG9mZnNldAoJaW50IDggLy8gaGVhZE9mZnNldAoJKwoJbG9hZCAwIC8vIGZ1bGwgYXJyYXkKCXN3YXAKCWludCA4CglleHRyYWN0MwoJYnRvaQoJYnl0ZSAid2lubmluZ1RpY2tldCIKCWFwcF9nbG9iYWxfZ2V0Cgk+PQoJYXNzZXJ0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEyOQoJLy8gc2VuZEFzc2V0VHJhbnNmZXIoewoJaXR4bl9iZWdpbgoJaW50IGF4ZmVyCglpdHhuX2ZpZWxkIFR5cGVFbnVtCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEzMAoJLy8gYXNzZXRSZWNlaXZlcjogdGhpcy50eG4uc2VuZGVyCgl0eG4gU2VuZGVyCglpdHhuX2ZpZWxkIEFzc2V0UmVjZWl2ZXIKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTMxCgkvLyB4ZmVyQXNzZXQ6IHRoaXMuYXNzZXQudmFsdWUKCWJ5dGUgImFzc2V0IgoJYXBwX2dsb2JhbF9nZXQKCWl0eG5fZmllbGQgWGZlckFzc2V0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEzMgoJLy8gYXNzZXRBbW91bnQ6IHRoaXMuYXBwLmFkZHJlc3MuYXNzZXRCYWxhbmNlKHRoaXMuYXNzZXQudmFsdWUpCgl0eG5hIEFwcGxpY2F0aW9ucyAwCglhcHBfcGFyYW1zX2dldCBBcHBBZGRyZXNzCglhc3NlcnQKCWJ5dGUgImFzc2V0IgoJYXBwX2dsb2JhbF9nZXQKCWFzc2V0X2hvbGRpbmdfZ2V0IEFzc2V0QmFsYW5jZQoJYXNzZXJ0CglpdHhuX2ZpZWxkIEFzc2V0QW1vdW50CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEzMwoJLy8gYXNzZXRDbG9zZVRvOiB0aGlzLnR4bi5zZW5kZXIKCXR4biBTZW5kZXIKCWl0eG5fZmllbGQgQXNzZXRDbG9zZVRvCgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjEzNAoJLy8gZmVlOiAwCglpbnQgMAoJaXR4bl9maWVsZCBGZWUKCWl0eG5fc3VibWl0CglyZXRzdWIKCmFiaV9yb3V0ZV9nZXRSZWZ1bmQ6CglieXRlIDB4OyBkdXAKCWNhbGxzdWIgZ2V0UmVmdW5kCglpbnQgMQoJcmV0dXJuCgpnZXRSZWZ1bmQ6Cglwcm90byAyIDAKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTQ0CgkvLyBhc3NlcnQoIXRoaXMud2lubmluZ1RpY2tldC5leGlzdHMpCgl0eG5hIEFwcGxpY2F0aW9ucyAwCglieXRlICJ3aW5uaW5nVGlja2V0IgoJYXBwX2dsb2JhbF9nZXRfZXgKCXN3YXAKCXBvcAoJIQoJYXNzZXJ0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE0NQoJLy8gYXNzZXJ0KGdsb2JhbHMucm91bmQgPiB0aGlzLmRyYXdSb3VuZC52YWx1ZSArIDE1MTIpCglnbG9iYWwgUm91bmQKCWJ5dGUgImRyYXdSb3VuZCIKCWFwcF9nbG9iYWxfZ2V0CglpbnQgMTUxMgoJKwoJPgoJYXNzZXJ0CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE0NwoJLy8gdGlja2V0UmFuZ2UgPSB0aGlzLnRpY2tldHModGhpcy50eG4uc2VuZGVyKS52YWx1ZQoJdHhuIFNlbmRlcgoJZnJhbWVfYnVyeSAtMSAvLyBzdG9yYWdlIGtleS8vdGlja2V0UmFuZ2UKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTQ4CgkvLyB0aWNrZXRDb3VudCA9IHRpY2tldFJhbmdlLmVuZCAtIHRpY2tldFJhbmdlLnN0YXJ0ICsgMQoJZnJhbWVfZGlnIC0xIC8vIHN0b3JhZ2Uga2V5Ly90aWNrZXRSYW5nZQoJYm94X2dldAoJYXNzZXJ0CglzdG9yZSAwIC8vIGZ1bGwgYXJyYXkKCWludCAwIC8vIGluaXRpYWwgb2Zmc2V0CglpbnQgOCAvLyBoZWFkT2Zmc2V0CgkrCglsb2FkIDAgLy8gZnVsbCBhcnJheQoJc3dhcAoJaW50IDgKCWV4dHJhY3QzCglidG9pCglmcmFtZV9kaWcgLTEgLy8gc3RvcmFnZSBrZXkvL3RpY2tldFJhbmdlCglib3hfZ2V0Cglhc3NlcnQKCXN0b3JlIDAgLy8gZnVsbCBhcnJheQoJaW50IDAgLy8gaW5pdGlhbCBvZmZzZXQKCWludCAwIC8vIGhlYWRPZmZzZXQKCSsKCWxvYWQgMCAvLyBmdWxsIGFycmF5Cglzd2FwCglpbnQgOAoJZXh0cmFjdDMKCWJ0b2kKCS0KCWludCAxCgkrCglmcmFtZV9idXJ5IC0yIC8vIHRpY2tldENvdW50OiB1aW50NjQKCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTUwCgkvLyB0aGlzLnRpY2tldHModGhpcy50eG4uc2VuZGVyKS5kZWxldGUoKQoJdHhuIFNlbmRlcgoJYm94X2RlbAoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxNTIKCS8vIHNlbmRQYXltZW50KHsKCWl0eG5fYmVnaW4KCWludCBwYXkKCWl0eG5fZmllbGQgVHlwZUVudW0KCgkvLyBleGFtcGxlcy9yYWZmbGUvcmFmZmxlLmFsZ28udHM6MTUzCgkvLyBhbW91bnQ6IHRoaXMudGlja2V0UHJpY2UudmFsdWUgKiB0aWNrZXRDb3VudAoJYnl0ZSAidGlja2V0UHJpY2UiCglhcHBfZ2xvYmFsX2dldAoJZnJhbWVfZGlnIC0yIC8vIHRpY2tldENvdW50OiB1aW50NjQKCSoKCWl0eG5fZmllbGQgQW1vdW50CgoJLy8gZXhhbXBsZXMvcmFmZmxlL3JhZmZsZS5hbGdvLnRzOjE1NAoJLy8gcmVjZWl2ZXI6IHRoaXMudHhuLnNlbmRlcgoJdHhuIFNlbmRlcgoJaXR4bl9maWVsZCBSZWNlaXZlcgoKCS8vIGV4YW1wbGVzL3JhZmZsZS9yYWZmbGUuYWxnby50czoxNTUKCS8vIGZlZTogMAoJaW50IDAKCWl0eG5fZmllbGQgRmVlCglpdHhuX3N1Ym1pdAoJcmV0c3ViCgpjcmVhdGVfTm9PcDoKCW1ldGhvZCAiY3JlYXRlQXBwbGljYXRpb24odWludDY0LHVpbnQ2NCl2b2lkIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uCgllcnIKCmNhbGxfTm9PcDoKCW1ldGhvZCAic2V0QXNzZXQoYXNzZXQpdm9pZCIKCW1ldGhvZCAic3RhcnRSYWZmbGUodWludDY0LHVpbnQ2NCl2b2lkIgoJbWV0aG9kICJidXlUaWNrZXRzKHBheSx1aW50NjQpdm9pZCIKCW1ldGhvZCAiZHJhdygpdm9pZCIKCW1ldGhvZCAiY2xhaW0oKXZvaWQiCgltZXRob2QgImdldFJlZnVuZCgpdm9pZCIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV9zZXRBc3NldCBhYmlfcm91dGVfc3RhcnRSYWZmbGUgYWJpX3JvdXRlX2J1eVRpY2tldHMgYWJpX3JvdXRlX2RyYXcgYWJpX3JvdXRlX2NsYWltIGFiaV9yb3V0ZV9nZXRSZWZ1bmQKCWVycg==", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDkKaW50IDE=" + }, + "contract": { + "name": "NFTRaffle", + "desc": "", + "methods": [ + { + "name": "createApplication", + "args": [ + { + "name": "ticketPrice", + "type": "uint64", + "desc": "The price of a single ticket (uALGO)" + }, + { + "name": "randomnessOracle", + "type": "uint64", + "desc": "The app ID of the randomness oracle" + } + ], + "desc": "Create the raffle", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "setAsset", + "args": [ + { + "name": "asset", + "type": "asset", + "desc": "The asset to be raffled" + } + ], + "desc": "Set the asset to be raffled", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "startRaffle", + "args": [ + { + "name": "end", + "type": "uint64", + "desc": "The round number when the raffle ends" + }, + { + "name": "draw", + "type": "uint64", + "desc": "The round number when the raffle is drawn" + } + ], + "desc": "Start the raffle", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "buyTickets", + "args": [ + { + "name": "payment", + "type": "pay", + "desc": "The payment for the tickets" + }, + { + "name": "quanity", + "type": "uint64", + "desc": "The number of tickets to buy" + } + ], + "desc": "Buy tickets. Note this can only be called once!It would be possible to allow multiple purchases, butfor simplicity, only one purchase is allowed.", + "returns": { + "type": "void", + "desc": "The total number of tickets owned by the sender" + } + }, + { + "name": "draw", + "args": [], + "desc": "Draw the winning ticket", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "claim", + "args": [], + "desc": "Send the asset to the the sender if they have the winning ticket", + "returns": { + "type": "void", + "desc": "" + } + }, + { + "name": "getRefund", + "args": [], + "desc": "Allows purchasers to get a refund if the winning ticket has not been drawnand 1512 rounds have passed since the draw round, meaning the oracle nolonger has the data for the draw round", + "returns": { + "type": "void", + "desc": "" + } + } + ] + } +} \ No newline at end of file diff --git a/examples/raffle/artifacts/NFTRaffle.src_map.json b/examples/raffle/artifacts/NFTRaffle.src_map.json new file mode 100644 index 000000000..7f8ed8181 --- /dev/null +++ b/examples/raffle/artifacts/NFTRaffle.src_map.json @@ -0,0 +1,3239 @@ +[ + { + "teal": 1, + "source": 8, + "pc": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119 + ] + }, + { + "teal": 13, + "source": 8, + "pc": [ + 120, + 121 + ] + }, + { + "teal": 14, + "source": 8, + "pc": [ + 122 + ] + }, + { + "teal": 15, + "source": 8, + "pc": [ + 123 + ] + }, + { + "teal": 16, + "source": 8, + "pc": [ + 124 + ] + }, + { + "teal": 17, + "source": 8, + "pc": [ + 125 + ] + }, + { + "teal": 18, + "source": 8, + "pc": [ + 126, + 127 + ] + }, + { + "teal": 19, + "source": 8, + "pc": [ + 128 + ] + }, + { + "teal": 20, + "source": 8, + "pc": [ + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144 + ] + }, + { + "teal": 23, + "source": 8, + "pc": [ + 145 + ] + }, + { + "teal": 33, + "source": 42, + "pc": [ + 146, + 147, + 148 + ] + }, + { + "teal": 34, + "source": 42, + "pc": [ + 149 + ] + }, + { + "teal": 37, + "source": 42, + "pc": [ + 150, + 151, + 152 + ] + }, + { + "teal": 38, + "source": 42, + "pc": [ + 153 + ] + }, + { + "teal": 41, + "source": 42, + "pc": [ + 154, + 155, + 156 + ] + }, + { + "teal": 42, + "source": 42, + "pc": [ + 157 + ] + }, + { + "teal": 43, + "source": 42, + "pc": [ + 158 + ] + }, + { + "teal": 46, + "source": 42, + "pc": [ + 159, + 160, + 161 + ] + }, + { + "teal": 50, + "source": 43, + "pc": [ + 162, + 163 + ] + }, + { + "teal": 51, + "source": 43, + "pc": [ + 164, + 165 + ] + }, + { + "teal": 52, + "source": 43, + "pc": [ + 166 + ] + }, + { + "teal": 56, + "source": 44, + "pc": [ + 167, + 168 + ] + }, + { + "teal": 57, + "source": 44, + "pc": [ + 169, + 170 + ] + }, + { + "teal": 58, + "source": 44, + "pc": [ + 171 + ] + }, + { + "teal": 59, + "source": 42, + "pc": [ + 172 + ] + }, + { + "teal": 68, + "source": 53, + "pc": [ + 173, + 174, + 175 + ] + }, + { + "teal": 69, + "source": 53, + "pc": [ + 176 + ] + }, + { + "teal": 70, + "source": 53, + "pc": [ + 177, + 178 + ] + }, + { + "teal": 73, + "source": 53, + "pc": [ + 179, + 180, + 181 + ] + }, + { + "teal": 74, + "source": 53, + "pc": [ + 182 + ] + }, + { + "teal": 75, + "source": 53, + "pc": [ + 183 + ] + }, + { + "teal": 78, + "source": 53, + "pc": [ + 184, + 185, + 186 + ] + }, + { + "teal": 82, + "source": 54, + "pc": [ + 187, + 188, + 189 + ] + }, + { + "teal": 83, + "source": 54, + "pc": [ + 190 + ] + }, + { + "teal": 84, + "source": 54, + "pc": [ + 191 + ] + }, + { + "teal": 85, + "source": 54, + "pc": [ + 192 + ] + }, + { + "teal": 86, + "source": 54, + "pc": [ + 193 + ] + }, + { + "teal": 87, + "source": 54, + "pc": [ + 194 + ] + }, + { + "teal": 88, + "source": 54, + "pc": [ + 195 + ] + }, + { + "teal": 97, + "source": 56, + "pc": [ + 196 + ] + }, + { + "teal": 98, + "source": 56, + "pc": [ + 197 + ] + }, + { + "teal": 99, + "source": 56, + "pc": [ + 198, + 199 + ] + }, + { + "teal": 103, + "source": 57, + "pc": [ + 200, + 201 + ] + }, + { + "teal": 104, + "source": 57, + "pc": [ + 202, + 203 + ] + }, + { + "teal": 108, + "source": 58, + "pc": [ + 204, + 205 + ] + }, + { + "teal": 109, + "source": 58, + "pc": [ + 206, + 207 + ] + }, + { + "teal": 113, + "source": 59, + "pc": [ + 208 + ] + }, + { + "teal": 114, + "source": 59, + "pc": [ + 209, + 210 + ] + }, + { + "teal": 118, + "source": 60, + "pc": [ + 211 + ] + }, + { + "teal": 119, + "source": 60, + "pc": [ + 212, + 213 + ] + }, + { + "teal": 122, + "source": 56, + "pc": [ + 214 + ] + }, + { + "teal": 126, + "source": 63, + "pc": [ + 215 + ] + }, + { + "teal": 127, + "source": 63, + "pc": [ + 216, + 217 + ] + }, + { + "teal": 128, + "source": 63, + "pc": [ + 218 + ] + }, + { + "teal": 129, + "source": 53, + "pc": [ + 219 + ] + }, + { + "teal": 139, + "source": 73, + "pc": [ + 220, + 221, + 222 + ] + }, + { + "teal": 140, + "source": 73, + "pc": [ + 223 + ] + }, + { + "teal": 143, + "source": 73, + "pc": [ + 224, + 225, + 226 + ] + }, + { + "teal": 144, + "source": 73, + "pc": [ + 227 + ] + }, + { + "teal": 147, + "source": 73, + "pc": [ + 228, + 229 + ] + }, + { + "teal": 148, + "source": 73, + "pc": [ + 230 + ] + }, + { + "teal": 149, + "source": 73, + "pc": [ + 231 + ] + }, + { + "teal": 150, + "source": 73, + "pc": [ + 232 + ] + }, + { + "teal": 151, + "source": 73, + "pc": [ + 233, + 234 + ] + }, + { + "teal": 152, + "source": 73, + "pc": [ + 235 + ] + }, + { + "teal": 153, + "source": 73, + "pc": [ + 236 + ] + }, + { + "teal": 154, + "source": 73, + "pc": [ + 237 + ] + }, + { + "teal": 157, + "source": 73, + "pc": [ + 238, + 239, + 240 + ] + }, + { + "teal": 158, + "source": 73, + "pc": [ + 241 + ] + }, + { + "teal": 159, + "source": 73, + "pc": [ + 242 + ] + }, + { + "teal": 162, + "source": 73, + "pc": [ + 243, + 244, + 245 + ] + }, + { + "teal": 171, + "source": 74, + "pc": [ + 246, + 247 + ] + }, + { + "teal": 172, + "source": 75, + "pc": [ + 248, + 249 + ] + }, + { + "teal": 173, + "source": 75, + "pc": [ + 250 + ] + }, + { + "teal": 174, + "source": 75, + "pc": [ + 251 + ] + }, + { + "teal": 175, + "source": 75, + "pc": [ + 252 + ] + }, + { + "teal": 178, + "source": 74, + "pc": [ + 253, + 254 + ] + }, + { + "teal": 179, + "source": 76, + "pc": [ + 255, + 256 + ] + }, + { + "teal": 180, + "source": 76, + "pc": [ + 257, + 258 + ] + }, + { + "teal": 181, + "source": 76, + "pc": [ + 259 + ] + }, + { + "teal": 182, + "source": 76, + "pc": [ + 260 + ] + }, + { + "teal": 185, + "source": 74, + "pc": [ + 261, + 262 + ] + }, + { + "teal": 186, + "source": 77, + "pc": [ + 263, + 264 + ] + }, + { + "teal": 187, + "source": 77, + "pc": [ + 265 + ] + }, + { + "teal": 188, + "source": 77, + "pc": [ + 266 + ] + }, + { + "teal": 189, + "source": 77, + "pc": [ + 267 + ] + }, + { + "teal": 190, + "source": 77, + "pc": [ + 268 + ] + }, + { + "teal": 194, + "source": 80, + "pc": [ + 269, + 270 + ] + }, + { + "teal": 195, + "source": 80, + "pc": [ + 271, + 272 + ] + }, + { + "teal": 196, + "source": 80, + "pc": [ + 273 + ] + }, + { + "teal": 197, + "source": 80, + "pc": [ + 274 + ] + }, + { + "teal": 201, + "source": 81, + "pc": [ + 275, + 276 + ] + }, + { + "teal": 202, + "source": 81, + "pc": [ + 277, + 278 + ] + }, + { + "teal": 203, + "source": 81, + "pc": [ + 279 + ] + }, + { + "teal": 207, + "source": 82, + "pc": [ + 280, + 281 + ] + }, + { + "teal": 208, + "source": 82, + "pc": [ + 282, + 283 + ] + }, + { + "teal": 209, + "source": 82, + "pc": [ + 284 + ] + }, + { + "teal": 210, + "source": 73, + "pc": [ + 285 + ] + }, + { + "teal": 224, + "source": 95, + "pc": [ + 286, + 287, + 288 + ] + }, + { + "teal": 225, + "source": 95, + "pc": [ + 289 + ] + }, + { + "teal": 228, + "source": 95, + "pc": [ + 290, + 291 + ] + }, + { + "teal": 229, + "source": 95, + "pc": [ + 292 + ] + }, + { + "teal": 230, + "source": 95, + "pc": [ + 293 + ] + }, + { + "teal": 231, + "source": 95, + "pc": [ + 294 + ] + }, + { + "teal": 232, + "source": 95, + "pc": [ + 295, + 296 + ] + }, + { + "teal": 233, + "source": 95, + "pc": [ + 297 + ] + }, + { + "teal": 234, + "source": 95, + "pc": [ + 298 + ] + }, + { + "teal": 235, + "source": 95, + "pc": [ + 299 + ] + }, + { + "teal": 238, + "source": 95, + "pc": [ + 300, + 301, + 302 + ] + }, + { + "teal": 239, + "source": 95, + "pc": [ + 303 + ] + }, + { + "teal": 240, + "source": 95, + "pc": [ + 304 + ] + }, + { + "teal": 243, + "source": 95, + "pc": [ + 305, + 306, + 307, + 308, + 309, + 310 + ] + }, + { + "teal": 247, + "source": 96, + "pc": [ + 311, + 312 + ] + }, + { + "teal": 248, + "source": 96, + "pc": [ + 313, + 314 + ] + }, + { + "teal": 249, + "source": 96, + "pc": [ + 315 + ] + }, + { + "teal": 250, + "source": 96, + "pc": [ + 316 + ] + }, + { + "teal": 251, + "source": 96, + "pc": [ + 317 + ] + }, + { + "teal": 255, + "source": 97, + "pc": [ + 318, + 319 + ] + }, + { + "teal": 256, + "source": 97, + "pc": [ + 320 + ] + }, + { + "teal": 257, + "source": 97, + "pc": [ + 321 + ] + }, + { + "teal": 258, + "source": 97, + "pc": [ + 322 + ] + }, + { + "teal": 262, + "source": 99, + "pc": [ + 323, + 324 + ] + }, + { + "teal": 263, + "source": 99, + "pc": [ + 325, + 326 + ] + }, + { + "teal": 264, + "source": 99, + "pc": [ + 327 + ] + }, + { + "teal": 265, + "source": 99, + "pc": [ + 328 + ] + }, + { + "teal": 266, + "source": 99, + "pc": [ + 329 + ] + }, + { + "teal": 267, + "source": 99, + "pc": [ + 330 + ] + }, + { + "teal": 268, + "source": 99, + "pc": [ + 331 + ] + }, + { + "teal": 272, + "source": 101, + "pc": [ + 332, + 333 + ] + }, + { + "teal": 273, + "source": 101, + "pc": [ + 334 + ] + }, + { + "teal": 274, + "source": 101, + "pc": [ + 335, + 336 + ] + }, + { + "teal": 275, + "source": 101, + "pc": [ + 337 + ] + }, + { + "teal": 276, + "source": 101, + "pc": [ + 338 + ] + }, + { + "teal": 277, + "source": 101, + "pc": [ + 339 + ] + }, + { + "teal": 278, + "source": 101, + "pc": [ + 340, + 341 + ] + }, + { + "teal": 282, + "source": 103, + "pc": [ + 342, + 343 + ] + }, + { + "teal": 283, + "source": 103, + "pc": [ + 344, + 345 + ] + }, + { + "teal": 284, + "source": 103, + "pc": [ + 346 + ] + }, + { + "teal": 285, + "source": 103, + "pc": [ + 347, + 348 + ] + }, + { + "teal": 289, + "source": 104, + "pc": [ + 349, + 350 + ] + }, + { + "teal": 290, + "source": 104, + "pc": [ + 351, + 352 + ] + }, + { + "teal": 291, + "source": 104, + "pc": [ + 353, + 354 + ] + }, + { + "teal": 292, + "source": 104, + "pc": [ + 355 + ] + }, + { + "teal": 293, + "source": 104, + "pc": [ + 356 + ] + }, + { + "teal": 294, + "source": 104, + "pc": [ + 357, + 358 + ] + }, + { + "teal": 295, + "source": 104, + "pc": [ + 359 + ] + }, + { + "teal": 296, + "source": 104, + "pc": [ + 360 + ] + }, + { + "teal": 297, + "source": 104, + "pc": [ + 361 + ] + }, + { + "teal": 298, + "source": 104, + "pc": [ + 362 + ] + }, + { + "teal": 299, + "source": 104, + "pc": [ + 363 + ] + }, + { + "teal": 303, + "source": 105, + "pc": [ + 364, + 365 + ] + }, + { + "teal": 304, + "source": 105, + "pc": [ + 366, + 367 + ] + }, + { + "teal": 305, + "source": 105, + "pc": [ + 368 + ] + }, + { + "teal": 306, + "source": 105, + "pc": [ + 369, + 370 + ] + }, + { + "teal": 307, + "source": 105, + "pc": [ + 371 + ] + }, + { + "teal": 308, + "source": 105, + "pc": [ + 372, + 373 + ] + }, + { + "teal": 317, + "source": 107, + "pc": [ + 374, + 375 + ] + }, + { + "teal": 318, + "source": 108, + "pc": [ + 376, + 377 + ] + }, + { + "teal": 319, + "source": 108, + "pc": [ + 378, + 379 + ] + }, + { + "teal": 320, + "source": 108, + "pc": [ + 380 + ] + }, + { + "teal": 321, + "source": 108, + "pc": [ + 381, + 382 + ] + }, + { + "teal": 322, + "source": 108, + "pc": [ + 383 + ] + }, + { + "teal": 323, + "source": 108, + "pc": [ + 384, + 385 + ] + }, + { + "teal": 324, + "source": 108, + "pc": [ + 386 + ] + }, + { + "teal": 325, + "source": 108, + "pc": [ + 387 + ] + }, + { + "teal": 326, + "source": 108, + "pc": [ + 388 + ] + }, + { + "teal": 329, + "source": 107, + "pc": [ + 389, + 390 + ] + }, + { + "teal": 330, + "source": 109, + "pc": [ + 391, + 392 + ] + }, + { + "teal": 331, + "source": 109, + "pc": [ + 393, + 394 + ] + }, + { + "teal": 332, + "source": 109, + "pc": [ + 395 + ] + }, + { + "teal": 333, + "source": 109, + "pc": [ + 396 + ] + }, + { + "teal": 336, + "source": 107, + "pc": [ + 397, + 398 + ] + }, + { + "teal": 337, + "source": 110, + "pc": [ + 399, + 400 + ] + }, + { + "teal": 338, + "source": 110, + "pc": [ + 401, + 402 + ] + }, + { + "teal": 339, + "source": 110, + "pc": [ + 403 + ] + }, + { + "teal": 340, + "source": 110, + "pc": [ + 404 + ] + }, + { + "teal": 344, + "source": 113, + "pc": [ + 405, + 406 + ] + }, + { + "teal": 345, + "source": 113, + "pc": [ + 407, + 408 + ] + }, + { + "teal": 346, + "source": 113, + "pc": [ + 409 + ] + }, + { + "teal": 347, + "source": 95, + "pc": [ + 410 + ] + }, + { + "teal": 350, + "source": 117, + "pc": [ + 411, + 412, + 413 + ] + }, + { + "teal": 355, + "source": 118, + "pc": [ + 414, + 415, + 416 + ] + }, + { + "teal": 356, + "source": 118, + "pc": [ + 417 + ] + }, + { + "teal": 357, + "source": 118, + "pc": [ + 418 + ] + }, + { + "teal": 358, + "source": 118, + "pc": [ + 419 + ] + }, + { + "teal": 359, + "source": 118, + "pc": [ + 420 + ] + }, + { + "teal": 360, + "source": 118, + "pc": [ + 421, + 422, + 423 + ] + }, + { + "teal": 365, + "source": 119, + "pc": [ + 424 + ] + }, + { + "teal": 366, + "source": 119, + "pc": [ + 425 + ] + }, + { + "teal": 367, + "source": 119, + "pc": [ + 426 + ] + }, + { + "teal": 368, + "source": 119, + "pc": [ + 427 + ] + }, + { + "teal": 369, + "source": 119, + "pc": [ + 428 + ] + }, + { + "teal": 370, + "source": 118, + "pc": [ + 429, + 430, + 431 + ] + }, + { + "teal": 381, + "source": 121, + "pc": [ + 432 + ] + }, + { + "teal": 382, + "source": 121, + "pc": [ + 433 + ] + }, + { + "teal": 383, + "source": 121, + "pc": [ + 434 + ] + }, + { + "teal": 384, + "source": 121, + "pc": [ + 435, + 436 + ] + }, + { + "teal": 385, + "source": 122, + "pc": [ + 437, + 438, + 439, + 440, + 441, + 442 + ] + }, + { + "teal": 386, + "source": 122, + "pc": [ + 443, + 444 + ] + }, + { + "teal": 390, + "source": 123, + "pc": [ + 445, + 446 + ] + }, + { + "teal": 391, + "source": 123, + "pc": [ + 447 + ] + }, + { + "teal": 392, + "source": 123, + "pc": [ + 448 + ] + }, + { + "teal": 393, + "source": 123, + "pc": [ + 449, + 450 + ] + }, + { + "teal": 394, + "source": 123, + "pc": [ + 451, + 452, + 453, + 454 + ] + }, + { + "teal": 395, + "source": 123, + "pc": [ + 455, + 456 + ] + }, + { + "teal": 399, + "source": 124, + "pc": [ + 457, + 458 + ] + }, + { + "teal": 400, + "source": 124, + "pc": [ + 459 + ] + }, + { + "teal": 401, + "source": 124, + "pc": [ + 460, + 461 + ] + }, + { + "teal": 405, + "source": 125, + "pc": [ + 462 + ] + }, + { + "teal": 406, + "source": 125, + "pc": [ + 463, + 464 + ] + }, + { + "teal": 410, + "source": 126, + "pc": [ + 465 + ] + }, + { + "teal": 411, + "source": 126, + "pc": [ + 466, + 467 + ] + }, + { + "teal": 414, + "source": 121, + "pc": [ + 468 + ] + }, + { + "teal": 415, + "source": 121, + "pc": [ + 469, + 470 + ] + }, + { + "teal": 416, + "source": 121, + "pc": [ + 471 + ] + }, + { + "teal": 417, + "source": 121, + "pc": [ + 472 + ] + }, + { + "teal": 418, + "source": 121, + "pc": [ + 473, + 474 + ] + }, + { + "teal": 419, + "source": 121, + "pc": [ + 475, + 476, + 477 + ] + }, + { + "teal": 420, + "source": 121, + "pc": [ + 478 + ] + }, + { + "teal": 423, + "source": 117, + "pc": [ + 479 + ] + }, + { + "teal": 430, + "source": 133, + "pc": [ + 480, + 481, + 482 + ] + }, + { + "teal": 431, + "source": 133, + "pc": [ + 483 + ] + }, + { + "teal": 432, + "source": 133, + "pc": [ + 484, + 485 + ] + }, + { + "teal": 435, + "source": 133, + "pc": [ + 486, + 487, + 488 + ] + }, + { + "teal": 436, + "source": 133, + "pc": [ + 489 + ] + }, + { + "teal": 437, + "source": 133, + "pc": [ + 490 + ] + }, + { + "teal": 440, + "source": 133, + "pc": [ + 491, + 492, + 493, + 494, + 495, + 496 + ] + }, + { + "teal": 444, + "source": 135, + "pc": [ + 497, + 498, + 499 + ] + }, + { + "teal": 445, + "source": 135, + "pc": [ + 500 + ] + }, + { + "teal": 446, + "source": 135, + "pc": [ + 501 + ] + }, + { + "teal": 447, + "source": 135, + "pc": [ + 502 + ] + }, + { + "teal": 448, + "source": 135, + "pc": [ + 503 + ] + }, + { + "teal": 449, + "source": 135, + "pc": [ + 504 + ] + }, + { + "teal": 450, + "source": 135, + "pc": [ + 505 + ] + }, + { + "teal": 454, + "source": 136, + "pc": [ + 506, + 507, + 508 + ] + }, + { + "teal": 458, + "source": 140, + "pc": [ + 509, + 510 + ] + }, + { + "teal": 459, + "source": 140, + "pc": [ + 511 + ] + }, + { + "teal": 460, + "source": 140, + "pc": [ + 512, + 513 + ] + }, + { + "teal": 464, + "source": 142, + "pc": [ + 514 + ] + }, + { + "teal": 465, + "source": 142, + "pc": [ + 515, + 516 + ] + }, + { + "teal": 470, + "source": 146, + "pc": [ + 517 + ] + }, + { + "teal": 471, + "source": 146, + "pc": [ + 518 + ] + }, + { + "teal": 472, + "source": 146, + "pc": [ + 519, + 520 + ] + }, + { + "teal": 473, + "source": 146, + "pc": [ + 521 + ] + }, + { + "teal": 474, + "source": 146, + "pc": [ + 522, + 523 + ] + }, + { + "teal": 478, + "source": 148, + "pc": [ + 524, + 525 + ] + }, + { + "teal": 479, + "source": 148, + "pc": [ + 526, + 527 + ] + }, + { + "teal": 480, + "source": 148, + "pc": [ + 528 + ] + }, + { + "teal": 481, + "source": 148, + "pc": [ + 529, + 530 + ] + }, + { + "teal": 485, + "source": 150, + "pc": [ + 531, + 532 + ] + }, + { + "teal": 486, + "source": 5, + "pc": [ + 533, + 534 + ] + }, + { + "teal": 487, + "source": 5, + "pc": [ + 535, + 536 + ] + }, + { + "teal": 488, + "source": 150, + "pc": [ + 537, + 538 + ] + }, + { + "teal": 489, + "source": 150, + "pc": [ + 539 + ] + }, + { + "teal": 490, + "source": 150, + "pc": [ + 540 + ] + }, + { + "teal": 491, + "source": 150, + "pc": [ + 541 + ] + }, + { + "teal": 492, + "source": 150, + "pc": [ + 542, + 543 + ] + }, + { + "teal": 493, + "source": 150, + "pc": [ + 544 + ] + }, + { + "teal": 494, + "source": 150, + "pc": [ + 545 + ] + }, + { + "teal": 495, + "source": 150, + "pc": [ + 546 + ] + }, + { + "teal": 496, + "source": 150, + "pc": [ + 547, + 548 + ] + }, + { + "teal": 497, + "source": 151, + "pc": [ + 549, + 550 + ] + }, + { + "teal": 498, + "source": 151, + "pc": [ + 551 + ] + }, + { + "teal": 499, + "source": 151, + "pc": [ + 552, + 553, + 554 + ] + }, + { + "teal": 500, + "source": 151, + "pc": [ + 555, + 556 + ] + }, + { + "teal": 501, + "source": 151, + "pc": [ + 557, + 558 + ] + }, + { + "teal": 502, + "source": 151, + "pc": [ + 559 + ] + }, + { + "teal": 503, + "source": 151, + "pc": [ + 560 + ] + }, + { + "teal": 506, + "source": 145, + "pc": [ + 561, + 562, + 563 + ] + }, + { + "teal": 511, + "source": 153, + "pc": [ + 564, + 565 + ] + }, + { + "teal": 512, + "source": 153, + "pc": [ + 566, + 567, + 568 + ] + }, + { + "teal": 517, + "source": 153, + "pc": [ + 569 + ] + }, + { + "teal": 518, + "source": 153, + "pc": [ + 570, + 571 + ] + }, + { + "teal": 519, + "source": 153, + "pc": [ + 572 + ] + }, + { + "teal": 520, + "source": 153, + "pc": [ + 573, + 574 + ] + }, + { + "teal": 521, + "source": 153, + "pc": [ + 575 + ] + }, + { + "teal": 522, + "source": 153, + "pc": [ + 576, + 577 + ] + }, + { + "teal": 523, + "source": 153, + "pc": [ + 578 + ] + }, + { + "teal": 524, + "source": 153, + "pc": [ + 579 + ] + }, + { + "teal": 525, + "source": 153, + "pc": [ + 580 + ] + }, + { + "teal": 526, + "source": 153, + "pc": [ + 581 + ] + }, + { + "teal": 531, + "source": 155, + "pc": [ + 582 + ] + }, + { + "teal": 532, + "source": 155, + "pc": [ + 583, + 584 + ] + }, + { + "teal": 533, + "source": 155, + "pc": [ + 585, + 586 + ] + }, + { + "teal": 534, + "source": 155, + "pc": [ + 587 + ] + }, + { + "teal": 535, + "source": 155, + "pc": [ + 588 + ] + }, + { + "teal": 539, + "source": 156, + "pc": [ + 589 + ] + }, + { + "teal": 540, + "source": 156, + "pc": [ + 590, + 591 + ] + }, + { + "teal": 541, + "source": 156, + "pc": [ + 592 + ] + }, + { + "teal": 542, + "source": 156, + "pc": [ + 593, + 594 + ] + }, + { + "teal": 543, + "source": 156, + "pc": [ + 595 + ] + }, + { + "teal": 544, + "source": 156, + "pc": [ + 596, + 597 + ] + }, + { + "teal": 545, + "source": 156, + "pc": [ + 598 + ] + }, + { + "teal": 546, + "source": 156, + "pc": [ + 599 + ] + }, + { + "teal": 547, + "source": 156, + "pc": [ + 600 + ] + }, + { + "teal": 548, + "source": 156, + "pc": [ + 601 + ] + }, + { + "teal": 555, + "source": 160, + "pc": [ + 602, + 603, + 604 + ] + }, + { + "teal": 556, + "source": 160, + "pc": [ + 605 + ] + }, + { + "teal": 557, + "source": 160, + "pc": [ + 606 + ] + }, + { + "teal": 560, + "source": 160, + "pc": [ + 607, + 608, + 609, + 610, + 611, + 612 + ] + }, + { + "teal": 564, + "source": 161, + "pc": [ + 613, + 614 + ] + }, + { + "teal": 565, + "source": 161, + "pc": [ + 615, + 616 + ] + }, + { + "teal": 569, + "source": 161, + "pc": [ + 617, + 618 + ] + }, + { + "teal": 570, + "source": 161, + "pc": [ + 619 + ] + }, + { + "teal": 571, + "source": 161, + "pc": [ + 620 + ] + }, + { + "teal": 572, + "source": 163, + "pc": [ + 621, + 622, + 623 + ] + }, + { + "teal": 573, + "source": 163, + "pc": [ + 624 + ] + }, + { + "teal": 574, + "source": 163, + "pc": [ + 625 + ] + }, + { + "teal": 575, + "source": 163, + "pc": [ + 626 + ] + }, + { + "teal": 576, + "source": 163, + "pc": [ + 627 + ] + }, + { + "teal": 577, + "source": 163, + "pc": [ + 628 + ] + }, + { + "teal": 581, + "source": 161, + "pc": [ + 629, + 630 + ] + }, + { + "teal": 582, + "source": 161, + "pc": [ + 631 + ] + }, + { + "teal": 583, + "source": 161, + "pc": [ + 632 + ] + }, + { + "teal": 584, + "source": 164, + "pc": [ + 633, + 634, + 635 + ] + }, + { + "teal": 585, + "source": 164, + "pc": [ + 636 + ] + }, + { + "teal": 586, + "source": 164, + "pc": [ + 637 + ] + }, + { + "teal": 587, + "source": 164, + "pc": [ + 638 + ] + }, + { + "teal": 588, + "source": 164, + "pc": [ + 639 + ] + }, + { + "teal": 589, + "source": 164, + "pc": [ + 640 + ] + }, + { + "teal": 599, + "source": 166, + "pc": [ + 641 + ] + }, + { + "teal": 600, + "source": 166, + "pc": [ + 642 + ] + }, + { + "teal": 601, + "source": 166, + "pc": [ + 643, + 644 + ] + }, + { + "teal": 605, + "source": 167, + "pc": [ + 645, + 646 + ] + }, + { + "teal": 606, + "source": 167, + "pc": [ + 647, + 648 + ] + }, + { + "teal": 610, + "source": 168, + "pc": [ + 649 + ] + }, + { + "teal": 611, + "source": 168, + "pc": [ + 650 + ] + }, + { + "teal": 612, + "source": 168, + "pc": [ + 651, + 652 + ] + }, + { + "teal": 616, + "source": 169, + "pc": [ + 653, + 654 + ] + }, + { + "teal": 617, + "source": 169, + "pc": [ + 655 + ] + }, + { + "teal": 618, + "source": 169, + "pc": [ + 656 + ] + }, + { + "teal": 619, + "source": 169, + "pc": [ + 657, + 658 + ] + }, + { + "teal": 620, + "source": 169, + "pc": [ + 659 + ] + }, + { + "teal": 621, + "source": 169, + "pc": [ + 660, + 661 + ] + }, + { + "teal": 625, + "source": 170, + "pc": [ + 662, + 663 + ] + }, + { + "teal": 626, + "source": 170, + "pc": [ + 664, + 665 + ] + }, + { + "teal": 630, + "source": 171, + "pc": [ + 666 + ] + }, + { + "teal": 631, + "source": 171, + "pc": [ + 667, + 668 + ] + }, + { + "teal": 634, + "source": 166, + "pc": [ + 669 + ] + }, + { + "teal": 635, + "source": 160, + "pc": [ + 670 + ] + }, + { + "teal": 644, + "source": 180, + "pc": [ + 671, + 672, + 673 + ] + }, + { + "teal": 645, + "source": 180, + "pc": [ + 674 + ] + }, + { + "teal": 646, + "source": 180, + "pc": [ + 675 + ] + }, + { + "teal": 649, + "source": 180, + "pc": [ + 676, + 677, + 678, + 679, + 680, + 681 + ] + }, + { + "teal": 653, + "source": 181, + "pc": [ + 682, + 683, + 684 + ] + }, + { + "teal": 654, + "source": 181, + "pc": [ + 685 + ] + }, + { + "teal": 655, + "source": 181, + "pc": [ + 686 + ] + }, + { + "teal": 656, + "source": 181, + "pc": [ + 687 + ] + }, + { + "teal": 657, + "source": 181, + "pc": [ + 688 + ] + }, + { + "teal": 658, + "source": 181, + "pc": [ + 689 + ] + }, + { + "teal": 659, + "source": 181, + "pc": [ + 690 + ] + }, + { + "teal": 663, + "source": 182, + "pc": [ + 691, + 692 + ] + }, + { + "teal": 664, + "source": 182, + "pc": [ + 693, + 694 + ] + }, + { + "teal": 665, + "source": 182, + "pc": [ + 695 + ] + }, + { + "teal": 666, + "source": 182, + "pc": [ + 696, + 697, + 698 + ] + }, + { + "teal": 667, + "source": 182, + "pc": [ + 699 + ] + }, + { + "teal": 668, + "source": 182, + "pc": [ + 700 + ] + }, + { + "teal": 669, + "source": 182, + "pc": [ + 701 + ] + }, + { + "teal": 673, + "source": 184, + "pc": [ + 702, + 703 + ] + }, + { + "teal": 674, + "source": 184, + "pc": [ + 704, + 705 + ] + }, + { + "teal": 678, + "source": 184, + "pc": [ + 706, + 707 + ] + }, + { + "teal": 679, + "source": 184, + "pc": [ + 708 + ] + }, + { + "teal": 680, + "source": 184, + "pc": [ + 709 + ] + }, + { + "teal": 681, + "source": 185, + "pc": [ + 710, + 711, + 712 + ] + }, + { + "teal": 682, + "source": 185, + "pc": [ + 713 + ] + }, + { + "teal": 683, + "source": 184, + "pc": [ + 714, + 715 + ] + }, + { + "teal": 684, + "source": 184, + "pc": [ + 716 + ] + }, + { + "teal": 685, + "source": 184, + "pc": [ + 717 + ] + }, + { + "teal": 686, + "source": 185, + "pc": [ + 718, + 719, + 720 + ] + }, + { + "teal": 687, + "source": 185, + "pc": [ + 721 + ] + }, + { + "teal": 688, + "source": 185, + "pc": [ + 722 + ] + }, + { + "teal": 689, + "source": 185, + "pc": [ + 723 + ] + }, + { + "teal": 690, + "source": 185, + "pc": [ + 724 + ] + }, + { + "teal": 691, + "source": 185, + "pc": [ + 725, + 726 + ] + }, + { + "teal": 695, + "source": 187, + "pc": [ + 727, + 728 + ] + }, + { + "teal": 696, + "source": 187, + "pc": [ + 729 + ] + }, + { + "teal": 704, + "source": 189, + "pc": [ + 730 + ] + }, + { + "teal": 705, + "source": 189, + "pc": [ + 731 + ] + }, + { + "teal": 706, + "source": 189, + "pc": [ + 732, + 733 + ] + }, + { + "teal": 710, + "source": 190, + "pc": [ + 734, + 735 + ] + }, + { + "teal": 711, + "source": 190, + "pc": [ + 736 + ] + }, + { + "teal": 712, + "source": 190, + "pc": [ + 737, + 738 + ] + }, + { + "teal": 713, + "source": 190, + "pc": [ + 739 + ] + }, + { + "teal": 714, + "source": 190, + "pc": [ + 740, + 741 + ] + }, + { + "teal": 718, + "source": 191, + "pc": [ + 742, + 743 + ] + }, + { + "teal": 719, + "source": 191, + "pc": [ + 744, + 745 + ] + }, + { + "teal": 723, + "source": 192, + "pc": [ + 746 + ] + }, + { + "teal": 724, + "source": 192, + "pc": [ + 747, + 748 + ] + }, + { + "teal": 727, + "source": 189, + "pc": [ + 749 + ] + }, + { + "teal": 728, + "source": 180, + "pc": [ + 750 + ] + }, + { + "teal": 731, + "source": 8, + "pc": [ + 751, + 752, + 753, + 754, + 755, + 756 + ] + }, + { + "teal": 732, + "source": 8, + "pc": [ + 757, + 758, + 759 + ] + }, + { + "teal": 733, + "source": 8, + "pc": [ + 760, + 761, + 762, + 763 + ] + }, + { + "teal": 734, + "source": 8, + "pc": [ + 764 + ] + }, + { + "teal": 737, + "source": 8, + "pc": [ + 765, + 766, + 767, + 768, + 769, + 770 + ] + }, + { + "teal": 738, + "source": 8, + "pc": [ + 771, + 772, + 773, + 774, + 775, + 776 + ] + }, + { + "teal": 739, + "source": 8, + "pc": [ + 777, + 778, + 779, + 780, + 781, + 782 + ] + }, + { + "teal": 740, + "source": 8, + "pc": [ + 783, + 784, + 785, + 786, + 787, + 788 + ] + }, + { + "teal": 741, + "source": 8, + "pc": [ + 789, + 790, + 791, + 792, + 793, + 794 + ] + }, + { + "teal": 742, + "source": 8, + "pc": [ + 795, + 796, + 797, + 798, + 799, + 800 + ] + }, + { + "teal": 743, + "source": 8, + "pc": [ + 801, + 802, + 803 + ] + }, + { + "teal": 744, + "source": 8, + "pc": [ + 804, + 805, + 806, + 807, + 808, + 809, + 810, + 811, + 812, + 813, + 814, + 815, + 816, + 817 + ] + }, + { + "teal": 745, + "source": 8, + "pc": [ + 818 + ] + } +] \ No newline at end of file diff --git a/examples/raffle/raffle.algo.ts b/examples/raffle/raffle.algo.ts new file mode 100644 index 000000000..0f71ecdac --- /dev/null +++ b/examples/raffle/raffle.algo.ts @@ -0,0 +1,202 @@ +import { Contract } from '../../src/lib/index'; + +type TicketRange = { start: number; end: number }; +// eslint-disable-next-line no-loss-of-precision +const RAND_MAX = 18_446_744_073_709_551_615; + +// eslint-disable-next-line no-unused-vars +class NFTRaffle extends Contract { + /** The app ID of the randomness oracle */ + randomnessOracle = GlobalStateKey(); + + /** The price of a single ticket (uALGO) */ + ticketPrice = GlobalStateKey(); + + /** The asset to be raffled */ + asset = GlobalStateKey(); + + /** After this round, tickets can no longer be purchased */ + endRound = GlobalStateKey(); + + /** The randomness oracle round commitment */ + drawRound = GlobalStateKey(); + + /** The range of tickets owned by each purchaser */ + tickets = BoxMap(); + + /** The total number of tickets purchased */ + totalTickets = GlobalStateKey(); + + /** The winning ticket number */ + winningTicket = GlobalStateKey(); + + randomBytes = GlobalStateKey(); + + /** + * Create the raffle + * + * @param ticketPrice The price of a single ticket (uALGO) + * @param randomnessOracle The app ID of the randomness oracle + * + */ + createApplication(ticketPrice: number, randomnessOracle: number): void { + this.randomnessOracle.value = randomnessOracle; + this.ticketPrice.value = ticketPrice; + } + + /** + * Set the asset to be raffled + * + * @param asset The asset to be raffled + * + */ + setAsset(asset: Asset): void { + assert(!this.asset.exists); + + sendAssetTransfer({ + assetReceiver: this.app.address, + xferAsset: asset, + assetAmount: 0, + fee: 0, + }); + + this.asset.value = asset; + } + + /** + * Start the raffle + * + * @param end The round number when the raffle ends + * @param draw The round number when the raffle is drawn + * + */ + startRaffle(axfer: AssetTransferTxn, end: number, draw: number): void { + verifyTxn(axfer, { + assetAmount: { greaterThan: 0 }, + assetReceiver: this.app.address, + xferAsset: this.asset.value, + }); + + assert(draw > end); + this.endRound.value = end; + this.drawRound.value = draw; + } + + /** + * Buy tickets. Note this can only be called once! + * It would be possible to allow multiple purchases, but + * for simplicity, only one purchase is allowed. + * + * @param payment The payment for the tickets + * @param quanity The number of tickets to buy + * + * @returns The total number of tickets owned by the sender + */ + buyTickets(payment: PayTxn, quantity: number): void { + assert(globals.round < this.endRound.value); + assert(quantity > 0); + + assert(!this.tickets(payment.sender).exists); + + const newTotal = this.totalTickets.value + quantity + 1; + + const preMBR = this.app.address.minBalance; + this.tickets(payment.sender).value = { start: this.totalTickets.value, end: newTotal - 1 }; + const mbrDelta = this.app.address.minBalance - preMBR; + + verifyTxn(payment, { + amount: this.ticketPrice.value * quantity + mbrDelta, + sender: this.txn.sender, + receiver: this.app.address, + }); + + this.totalTickets.value = newTotal; + } + + /** Get randomness from the oracle or by hashing existing randomness */ + private getRandomBytes(): void { + if (this.randomBytes.exists) { + this.randomBytes.value = sha256(this.randomBytes.value) as bytes; + } else { + this.randomBytes.value = sendMethodCall<[uint64, bytes], bytes>({ + name: 'must_get', + methodArgs: [this.drawRound.value, ''], + applicationID: Application.fromID(this.randomnessOracle.value), + fee: 0, + onCompletion: OnCompletion.NoOp, + }); + } + } + + /** Draw the winning ticket */ + // eslint-disable-next-line no-unused-vars + draw(_oracleReference: Application): boolean { + // assert(this.endRound.value < globals.round); + assert(!this.winningTicket.exists); + this.getRandomBytes(); + + // Continue to sample a uint64 from randomBytes until we get one that avoids modulo bias + // See https://stackoverflow.com/a/46991999/12513465 + const n = this.totalTickets.value; + let x: uint64; + let offset = 0; + let maxCondition: boolean; + + do { + x = extract_uint64(this.randomBytes.value, offset); + + offset = offset + 8; + + maxCondition = x > RAND_MAX - (((RAND_MAX % n) + 1) % n); + } while (maxCondition && offset < 32); + + if (maxCondition) return false; + + this.winningTicket.value = x % n; + return true; + } + + /** Send the asset to the the sender if they have the winning ticket */ + claim(): void { + const ticketRange = this.tickets(this.txn.sender).value; + + assert(ticketRange.start <= this.winningTicket.value); + assert(ticketRange.end >= this.winningTicket.value); + + sendAssetTransfer({ + assetReceiver: this.txn.sender, + xferAsset: this.asset.value, + assetAmount: this.app.address.assetBalance(this.asset.value), + assetCloseTo: this.txn.sender, + fee: 0, + }); + } + + /** + * Allows purchasers to get a refund if the winning ticket has not been drawn + * and 1512 rounds have passed since the draw round, meaning the oracle no + * longer has the data for the draw round + */ + getRefund(): void { + assert(!this.winningTicket.exists); + assert(globals.round > this.drawRound.value + 1512); + + const ticketRange = this.tickets(this.txn.sender).value; + const ticketCount = ticketRange.end - ticketRange.start + 1; + + this.tickets(this.txn.sender).delete(); + + sendPayment({ + amount: this.ticketPrice.value * ticketCount, + receiver: this.txn.sender, + fee: 0, + }); + } +} + +// eslint-disable-next-line no-unused-vars +class MockVRFBeacon extends Contract { + must_get(_round: uint64, data: bytes): bytes { + return sha256(data + itob(globals.round)) as bytes; + } +} diff --git a/examples/raffle/raffle.test.ts b/examples/raffle/raffle.test.ts new file mode 100644 index 000000000..a665b41ff --- /dev/null +++ b/examples/raffle/raffle.test.ts @@ -0,0 +1,137 @@ +import { describe, test, beforeAll, beforeEach, expect } from '@jest/globals'; +// eslint-disable-next-line import/no-unresolved +import { algorandFixture } from '@algorandfoundation/algokit-utils/testing'; +import * as algokit from '@algorandfoundation/algokit-utils'; +import algosdk from 'algosdk'; +import { MockVrfBeaconClient } from './MockVRFBeaconClient'; +import { NftRaffleClient } from './NFTRaffleClient'; + +const BOX_COST = 21_700; + +describe('Raffle', () => { + const fixture = algorandFixture(); + + let appClient: NftRaffleClient; + + let asa: bigint; + + let alice: algosdk.Account; + + let bob: algosdk.Account; + + let randomnessOracle: bigint; + + beforeEach(fixture.beforeEach); + + beforeAll(async () => { + await fixture.beforeEach(); + const { algod, testAccount } = fixture.context; + + const beaconClient = new MockVrfBeaconClient( + { + sender: testAccount, + resolveBy: 'id', + id: 0, + }, + algod + ); + + await beaconClient.create.createApplication({}); + + randomnessOracle = BigInt((await beaconClient.appClient.getAppReference()).appId); + + alice = testAccount; + + appClient = new NftRaffleClient( + { + sender: testAccount, + resolveBy: 'id', + id: 0, + }, + algod + ); + + await appClient.create.createApplication({ + ticketPrice: 100, + randomnessOracle, + }); + + const asaCreateTxn = algosdk.makeAssetCreateTxnWithSuggestedParamsFromObject({ + suggestedParams: await algod.getTransactionParams().do(), + from: testAccount.addr, + total: 1, + decimals: 0, + defaultFrozen: false, + }); + + const { confirmation } = await algokit.sendTransaction({ transaction: asaCreateTxn, from: testAccount }, algod); + + asa = BigInt(confirmation!.assetIndex!); + + await appClient.appClient.fundAppAccount(algokit.microAlgos(200_000)); + }); + + test('setAsset', async () => { + await appClient.setAsset({ asset: asa }, { sendParams: { fee: algokit.microAlgos(2_000) } }); + }); + + test('startRaffle', async () => { + const { algod } = fixture.context; + + const lastRound = BigInt((await algod.status().do())['last-round']); + + const axfer = algosdk.makeAssetTransferTxnWithSuggestedParamsFromObject({ + from: alice.addr, + assetIndex: Number(asa), + to: (await appClient.appClient.getAppReference()).appAddress, + suggestedParams: await algod.getTransactionParams().do(), + amount: 1, + }); + + await appClient.startRaffle({ axfer, end: lastRound + BigInt(100), draw: lastRound + BigInt(101) }); + }); + + test('buyTickets', async () => { + const { algod, testAccount } = fixture.context; + + bob = testAccount; + + const ticketPrice = (await appClient.getGlobalState()).ticketPrice!.asNumber(); + const quantity = 50; + + const to = (await appClient.appClient.getAppReference()).appAddress; + + const alicePayment = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ + from: alice.addr, + to, + suggestedParams: await algod.getTransactionParams().do(), + amount: ticketPrice * quantity + BOX_COST, + }); + + await appClient.buyTickets( + { payment: alicePayment, quantity: 50 }, + { boxes: [algosdk.decodeAddress(alice.addr).publicKey] } + ); + + const bobPayment = algosdk.makePaymentTxnWithSuggestedParamsFromObject({ + from: bob.addr, + to, + suggestedParams: await algod.getTransactionParams().do(), + amount: ticketPrice * quantity + BOX_COST, + }); + + await appClient.buyTickets( + { payment: bobPayment, quantity: 50 }, + { sender: bob, boxes: [algosdk.decodeAddress(bob.addr).publicKey] } + ); + }); + + test('draw', async () => { + const result = await appClient.draw( + { _oracleReference: randomnessOracle }, + { sendParams: { fee: algokit.microAlgos(2_000) } } + ); + + expect(result.return?.valueOf()).toBe(true); + }); +}); diff --git a/examples/raffle/tsconfig.json b/examples/raffle/tsconfig.json new file mode 100644 index 000000000..5e3106d17 --- /dev/null +++ b/examples/raffle/tsconfig.json @@ -0,0 +1,103 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/package.json b/package.json index 23fb5ce0a..f3cdc5f3a 100644 --- a/package.json +++ b/package.json @@ -42,12 +42,13 @@ "compile-non_abi": "bun ./src/bin/tealscript.ts --unsafe-disable-typescript examples/non_abi/non_abi.algo.ts examples/non_abi/artifacts", "compile-optin-lsig": "bun ./src/bin/tealscript.ts --unsafe-disable-typescript examples/optin-lsig/lsig.algo.ts examples/optin-lsig/artifacts", "compile-lsig_with_app": "bun ./src/bin/tealscript.ts --unsafe-disable-typescript examples/lsig_with_app/lsig_with_app.algo.ts examples/lsig_with_app/artifacts", + "compile-raffle": "bun ./src/bin/tealscript.ts examples/raffle/raffle.algo.ts examples/raffle/artifacts && algokitgen generate -a examples/raffle/artifacts/NFTRaffle.arc32.json -o examples/raffle/NFTRaffleClient.ts && algokitgen generate -a examples/raffle/artifacts/MockVRFBeacon.arc32.json -o examples/raffle/MockVRFBeaconClient.ts", "run-merkle": "bun examples/merkle/demo.ts", "run-tuple_in_box": "bun ./examples/tuple_in_box/client.ts", "run-itxns": "bun examples/itxns/demo.ts", "run-examples": "conc \"bun run-merkle\" \"bun run-tuple_in_box\" \"bun run-itxns\"", "run-simple": "bun examples/simple/index.ts", - "compile-examples": "conc \"bun compile-amm\" \"bun compile-arc75\" \"bun compile-auction\" \"bun compile-itxns\" \"bun compile-simple\" \"bun compile-tuple_in_box\" \"bun compile-calculator\" \"bun compile-merkle\" \"bun compile-big_box\" \"bun compile-arc72\" \"bun compile-non_abi\" \"bun compile-optin-lsig\" \"bun compile-lsig_with_app\"", + "compile-examples": "conc \"bun compile-amm\" \"bun compile-arc75\" \"bun compile-auction\" \"bun compile-itxns\" \"bun compile-simple\" \"bun compile-tuple_in_box\" \"bun compile-calculator\" \"bun compile-merkle\" \"bun compile-big_box\" \"bun compile-arc72\" \"bun compile-non_abi\" \"bun compile-optin-lsig\" \"bun compile-lsig_with_app\" \"bun compile-raffle\"", "webpack-smoketest": "webpack --config tests/web/webpack.config.js", "pre-commit": "conc \"bun lint\" \"bun test\" \"bun test examples/\" \"bun run-examples\" \"bun webpack-smoketest\" \"bun scripts/compile_all_smoketest.ts\"", "compile-all": "conc \"bun compile-tests\" \"bun compile-examples\"" diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index 6b5f505a6..ed8554480 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -5034,9 +5034,12 @@ export default class Compiler { this.pushComments(p); if (key === 'onCompletion') { - if (!ts.isPropertyAssignment(p) || !ts.isStringLiteral(p.initializer)) - throw new Error('OnCompletion key must be a string'); - this.pushVoid(p.initializer, `int ${p.initializer.text}`); + if (!ts.isPropertyAssignment(p) || !ts.isPropertyAccessExpression(p.initializer)) + throw new Error('OnCompletion expects OnCompletion enum'); + this.pushVoid( + p.initializer, + `int ${ON_COMPLETES.indexOf(p.initializer.name.getText() as OnComplete)} // ${p.initializer.name.getText()}` + ); this.pushVoid(p, 'itxn_field OnCompletion'); } else if (key === 'methodArgs') { if (typeArgs === undefined || !ts.isTupleTypeNode(typeArgs[0]))