Skip to content

Commit fa2f3af

Browse files
committed
fix: do not encode reference types as foreign array index
1 parent 73842b7 commit fa2f3af

File tree

8 files changed

+48
-15
lines changed

8 files changed

+48
-15
lines changed

src/context-helpers/internal-context.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ class InternalContext {
4343
return this.ledger.getApplication(this.activeGroup.activeApplicationId)
4444
}
4545

46+
get hasActiveGroup(): boolean {
47+
return this.value.txn.hasActiveGroup
48+
}
49+
4650
get activeGroup(): TransactionGroup {
4751
return this.value.txn.activeGroup
4852
}

src/impl/app-global.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ export const AppGlobal: typeof op.AppGlobal = {
1111
lazyContext.ledger.setGlobalState(lazyContext.activeApplication, asBytes(a), undefined)
1212
},
1313
getBytes(a: StubBytesCompat): bytes {
14-
return this.getExBytes(0, asBytes(a))[0]
14+
const app = lazyContext.activeApplication
15+
return this.getExBytes(app, asBytes(a))[0]
1516
},
1617
getUint64(a: StubBytesCompat): uint64 {
17-
return this.getExUint64(0, asBytes(a))[0]
18+
const app = lazyContext.activeApplication
19+
return this.getExUint64(app, asBytes(a))[0]
1820
},
1921
getExBytes(a: Application | StubUint64Compat, b: StubBytesCompat): readonly [bytes, boolean] {
2022
const app = getApp(a)

src/impl/app-local.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ export const AppLocal: typeof op.AppLocal = {
1414
lazyContext.ledger.setLocalState(app, account, asBytes(b), undefined)
1515
},
1616
getBytes: function (a: Account | StubUint64Compat, b: StubBytesCompat): bytes {
17+
const app = lazyContext.activeApplication
1718
const account = getAccount(a)
18-
return this.getExBytes(account, 0, asBytes(b))[0]
19+
return this.getExBytes(account, app, asBytes(b))[0]
1920
},
2021
getUint64: function (a: Account | StubUint64Compat, b: StubBytesCompat): uint64 {
22+
const app = lazyContext.activeApplication
2123
const account = getAccount(a)
22-
return this.getExUint64(account, 0, asBytes(b))[0]
24+
return this.getExUint64(account, app, asBytes(b))[0]
2325
},
2426
getExBytes: function (a: Account | StubUint64Compat, b: Application | StubUint64Compat, c: StubBytesCompat): readonly [bytes, boolean] {
2527
const app = getApp(b)

src/impl/encoded-types/encoded-types.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ import {
1919
import { encodingUtil } from '@algorandfoundation/puya-ts'
2020
import assert from 'assert'
2121
import { ABI_RETURN_VALUE_LOG_PREFIX, ALGORAND_ADDRESS_BYTE_LENGTH, ALGORAND_CHECKSUM_BYTE_LENGTH, UINT64_SIZE } from '../../constants'
22-
import { lazyContext } from '../../context-helpers/internal-context'
2322
import { AvmError, avmInvariant, CodeError, InternalError } from '../../errors'
2423
import { nameOfType, type DeliberateAny } from '../../typescript-helpers'
2524
import {
@@ -42,7 +41,6 @@ import { BytesBackedCls, Uint64BackedCls } from '../base'
4241
import type { StubBytesCompat } from '../primitives'
4342
import { BigUintCls, Bytes, BytesCls, getUint8Array, isBytes, Uint64Cls } from '../primitives'
4443
import { Account, AccountCls, ApplicationCls, AssetCls } from '../reference'
45-
import type { ApplicationCallTransaction } from '../transactions'
4644
import { arrayProxyHandler } from './array-proxy'
4745
import { ABI_LENGTH_SIZE, FALSE_BIGINT_VALUE, IS_INITIALISING_FROM_BYTES_SYMBOL, TRUE_BIGINT_VALUE } from './constants'
4846
import {
@@ -1157,16 +1155,13 @@ export const getArc4Encoded = (value: DeliberateAny, sourceTypeInfoString?: stri
11571155
return value
11581156
}
11591157
if (value instanceof AccountCls) {
1160-
const index = (lazyContext.activeGroup.activeTransaction as ApplicationCallTransaction).apat.indexOf(value)
1161-
return index >= 0 ? new Uint({ name: 'Uint<64>', genericArgs: [{ name: '64' }] }, asBigInt(index)) : getArc4Encoded(value.bytes)
1158+
return getArc4Encoded(value.bytes)
11621159
}
11631160
if (value instanceof AssetCls) {
1164-
const index = (lazyContext.activeGroup.activeTransaction as ApplicationCallTransaction).apas.indexOf(value)
1165-
return index >= 0 ? new Uint({ name: 'Uint<64>', genericArgs: [{ name: '64' }] }, asBigInt(index)) : getArc4Encoded(value.id)
1161+
return getArc4Encoded(value.id)
11661162
}
11671163
if (value instanceof ApplicationCls) {
1168-
const index = (lazyContext.activeGroup.activeTransaction as ApplicationCallTransaction).apfa.indexOf(value)
1169-
return index >= 0 ? new Uint({ name: 'Uint<64>', genericArgs: [{ name: '64' }] }, asBigInt(index)) : getArc4Encoded(value.id)
1164+
return getArc4Encoded(value.id)
11701165
}
11711166
if (typeof value === 'boolean') {
11721167
return new Bool({ name: 'Bool' }, value)

src/impl/state.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ export class BoxCls<TValue> {
246246
}
247247

248248
get ref(): BoxRefCls {
249-
return new BoxRefCls(this.key)
249+
return new BoxRefCls(this.key, this.#app)
250250
}
251251

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

320-
constructor(key?: StubBytesCompat) {
320+
constructor(key?: StubBytesCompat, app?: Application) {
321321
this.#key = key ? asBytes(key) : undefined
322-
this.#app = lazyContext.activeApplication
322+
this.#app = app ?? lazyContext.activeApplication
323323
}
324324

325325
get hasKey(): boolean {

src/subcontexts/transaction-context.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ export class TransactionContext {
146146
}
147147
}
148148

149+
get hasActiveGroup(): boolean {
150+
return !!this.#activeGroup
151+
}
152+
149153
/**
150154
* Gets the active transaction group.
151155
* @returns The active transaction group.

tests/artifacts/state-ops/contract.algo.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
arc4,
44
assert,
55
BaseContract,
6+
BoxMap,
67
Bytes,
78
clone,
89
contract,
@@ -907,3 +908,15 @@ export class LocalStateContract extends arc4.Contract {
907908
return this.arc4DynamicBytes(a).value
908909
}
909910
}
911+
912+
export class BoxMapContract extends arc4.Contract {
913+
allowedCreators = BoxMap<[Account, Account], boolean>({
914+
keyPrefix: Bytes(),
915+
})
916+
917+
allowOptInsFrom(creator: Account): void {
918+
assert(Txn.accounts(0) === Txn.sender)
919+
assert(Txn.applications(0) === Global.currentApplicationId)
920+
this.allowedCreators([Txn.sender, creator]).value = true
921+
}
922+
}

tests/state-op-codes.algo.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import type { DeliberateAny } from '../src/typescript-helpers'
1717
import { asBigInt, asNumber, asUint64Cls, asUint8Array, getRandomBytes } from '../src/util'
1818
import { AppExpectingEffects } from './artifacts/created-app-asset/contract.algo'
1919
import {
20+
BoxMapContract,
2021
ItxnDemoContract,
2122
ITxnOpsContract,
2223
StateAcctParamsGetContract,
@@ -767,6 +768,18 @@ describe('State op codes', async () => {
767768
expect(bytesResult).toEqual(bytesAvmResult)
768769
})
769770
})
771+
772+
describe('BoxMap', async () => {
773+
test('should be able to use tuple of reference types as key', () => {
774+
const creatorVerifier = ctx.contract.create(BoxMapContract)
775+
const creator = ctx.any.arc4.address()
776+
777+
creatorVerifier.allowOptInsFrom(creator.native)
778+
779+
const isAllowed = creatorVerifier.allowedCreators([ctx.defaultSender, creator.native]).value
780+
expect(isAllowed).toBe(true)
781+
})
782+
})
770783
})
771784
const tryOptIn = async (client: AppClient) => {
772785
try {

0 commit comments

Comments
 (0)