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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/context-helpers/internal-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ class InternalContext {
return this.ledger.getApplication(this.activeGroup.activeApplicationId)
}

get hasActiveGroup(): boolean {
return this.value.txn.hasActiveGroup
}

get activeGroup(): TransactionGroup {
return this.value.txn.activeGroup
}
Expand Down
6 changes: 4 additions & 2 deletions src/impl/app-global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ export const AppGlobal: typeof op.AppGlobal = {
lazyContext.ledger.setGlobalState(lazyContext.activeApplication, asBytes(a), undefined)
},
getBytes(a: StubBytesCompat): bytes {
return this.getExBytes(0, asBytes(a))[0]
const app = lazyContext.activeApplication
return this.getExBytes(app, asBytes(a))[0]
},
getUint64(a: StubBytesCompat): uint64 {
return this.getExUint64(0, asBytes(a))[0]
const app = lazyContext.activeApplication
return this.getExUint64(app, asBytes(a))[0]
},
getExBytes(a: Application | StubUint64Compat, b: StubBytesCompat): readonly [bytes, boolean] {
const app = getApp(a)
Expand Down
6 changes: 4 additions & 2 deletions src/impl/app-local.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ export const AppLocal: typeof op.AppLocal = {
lazyContext.ledger.setLocalState(app, account, asBytes(b), undefined)
},
getBytes: function (a: Account | StubUint64Compat, b: StubBytesCompat): bytes {
const app = lazyContext.activeApplication
const account = getAccount(a)
return this.getExBytes(account, 0, asBytes(b))[0]
return this.getExBytes(account, app, asBytes(b))[0]
},
getUint64: function (a: Account | StubUint64Compat, b: StubBytesCompat): uint64 {
const app = lazyContext.activeApplication
const account = getAccount(a)
return this.getExUint64(account, 0, asBytes(b))[0]
return this.getExUint64(account, app, asBytes(b))[0]
},
getExBytes: function (a: Account | StubUint64Compat, b: Application | StubUint64Compat, c: StubBytesCompat): readonly [bytes, boolean] {
const app = getApp(b)
Expand Down
11 changes: 3 additions & 8 deletions src/impl/encoded-types/encoded-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import {
import { encodingUtil } from '@algorandfoundation/puya-ts'
import assert from 'assert'
import { ABI_RETURN_VALUE_LOG_PREFIX, ALGORAND_ADDRESS_BYTE_LENGTH, ALGORAND_CHECKSUM_BYTE_LENGTH, UINT64_SIZE } from '../../constants'
import { lazyContext } from '../../context-helpers/internal-context'
import { AvmError, avmInvariant, CodeError, InternalError } from '../../errors'
import { nameOfType, type DeliberateAny } from '../../typescript-helpers'
import {
Expand All @@ -42,7 +41,6 @@ import { BytesBackedCls, Uint64BackedCls } from '../base'
import type { StubBytesCompat } from '../primitives'
import { BigUintCls, Bytes, BytesCls, getUint8Array, isBytes, Uint64Cls } from '../primitives'
import { Account, AccountCls, ApplicationCls, AssetCls } from '../reference'
import type { ApplicationCallTransaction } from '../transactions'
import { arrayProxyHandler } from './array-proxy'
import { ABI_LENGTH_SIZE, FALSE_BIGINT_VALUE, IS_INITIALISING_FROM_BYTES_SYMBOL, TRUE_BIGINT_VALUE } from './constants'
import {
Expand Down Expand Up @@ -1157,16 +1155,13 @@ export const getArc4Encoded = (value: DeliberateAny, sourceTypeInfoString?: stri
return value
}
if (value instanceof AccountCls) {
const index = (lazyContext.activeGroup.activeTransaction as ApplicationCallTransaction).apat.indexOf(value)
return index >= 0 ? new Uint({ name: 'Uint<64>', genericArgs: [{ name: '64' }] }, asBigInt(index)) : getArc4Encoded(value.bytes)
return getArc4Encoded(value.bytes)
}
if (value instanceof AssetCls) {
const index = (lazyContext.activeGroup.activeTransaction as ApplicationCallTransaction).apas.indexOf(value)
return index >= 0 ? new Uint({ name: 'Uint<64>', genericArgs: [{ name: '64' }] }, asBigInt(index)) : getArc4Encoded(value.id)
return getArc4Encoded(value.id)
}
if (value instanceof ApplicationCls) {
const index = (lazyContext.activeGroup.activeTransaction as ApplicationCallTransaction).apfa.indexOf(value)
return index >= 0 ? new Uint({ name: 'Uint<64>', genericArgs: [{ name: '64' }] }, asBigInt(index)) : getArc4Encoded(value.id)
return getArc4Encoded(value.id)
}
if (typeof value === 'boolean') {
return new Bool({ name: 'Bool' }, value)
Expand Down
6 changes: 3 additions & 3 deletions src/impl/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ export class BoxCls<TValue> {
}

get ref(): BoxRefCls {
return new BoxRefCls(this.key)
return new BoxRefCls(this.key, this.#app)
}

get(options: { default: TValue }): TValue {
Expand Down Expand Up @@ -317,9 +317,9 @@ export class BoxRefCls {
return x instanceof Object && '_type' in x && (x as { _type: string })['_type'] === BoxRefCls.name
}

constructor(key?: StubBytesCompat) {
constructor(key?: StubBytesCompat, app?: Application) {
this.#key = key ? asBytes(key) : undefined
this.#app = lazyContext.activeApplication
this.#app = app ?? lazyContext.activeApplication
}

get hasKey(): boolean {
Expand Down
4 changes: 4 additions & 0 deletions src/subcontexts/transaction-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ export class TransactionContext {
}
}

get hasActiveGroup(): boolean {
return !!this.#activeGroup
}

/**
* Gets the active transaction group.
* @returns The active transaction group.
Expand Down
13 changes: 13 additions & 0 deletions tests/artifacts/state-ops/contract.algo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
arc4,
assert,
BaseContract,
BoxMap,
Bytes,
clone,
contract,
Expand Down Expand Up @@ -907,3 +908,15 @@ export class LocalStateContract extends arc4.Contract {
return this.arc4DynamicBytes(a).value
}
}

export class BoxMapContract extends arc4.Contract {
allowedCreators = BoxMap<[Account, Account], boolean>({
keyPrefix: Bytes(),
})

allowOptInsFrom(creator: Account): void {
assert(Txn.accounts(0) === Txn.sender)
assert(Txn.applications(0) === Global.currentApplicationId)
this.allowedCreators([Txn.sender, creator]).value = true
}
}
13 changes: 13 additions & 0 deletions tests/state-op-codes.algo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type { DeliberateAny } from '../src/typescript-helpers'
import { asBigInt, asNumber, asUint64Cls, asUint8Array, getRandomBytes } from '../src/util'
import { AppExpectingEffects } from './artifacts/created-app-asset/contract.algo'
import {
BoxMapContract,
ItxnDemoContract,
ITxnOpsContract,
StateAcctParamsGetContract,
Expand Down Expand Up @@ -767,6 +768,18 @@ describe('State op codes', async () => {
expect(bytesResult).toEqual(bytesAvmResult)
})
})

describe('BoxMap', async () => {
test('should be able to use tuple of reference types as key', () => {
const creatorVerifier = ctx.contract.create(BoxMapContract)
const creator = ctx.any.arc4.address()

creatorVerifier.allowOptInsFrom(creator.native)

const isAllowed = creatorVerifier.allowedCreators([ctx.defaultSender, creator.native]).value
expect(isAllowed).toBe(true)
})
})
})
const tryOptIn = async (client: AppClient) => {
try {
Expand Down