Skip to content

Commit 6c987a4

Browse files
authored
Merge pull request #6 from algorandfoundation/feat-app-global
feat: implement AppGlobal and add tests for it
2 parents c2b789d + b3b8405 commit 6c987a4

32 files changed

+1111
-106
lines changed

.editorconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[*]
2+
charset = utf-8
3+
insert_final_newline = true
4+
end_of_line = lf
5+
indent_style = space
6+
indent_size = 2
7+
tab_width = 2
8+
max_line_length = 140
9+
trim_trailing_whitespace = true

.gitattributes

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Set the repository to show as TypeScript rather than JS in GitHub
2+
*.js linguist-detectable=false
3+
4+
# Treat text as lf
5+
* text=auto
6+
* eol=lf

.vscode/settings.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"editor.formatOnSave": true,
3+
"editor.defaultFormatter": "esbenp.prettier-vscode",
4+
"editor.codeActionsOnSave": {
5+
"source.fixAll.eslint": "explicit",
6+
"source.organizeImports": "explicit"
7+
},
8+
"eslint.validate": ["typescript"],
9+
"eslint.options": {
10+
"extensions": [".ts"]
11+
},
12+
"typescript.preferences.quoteStyle": "single",
13+
"yaml.schemas": {
14+
"https://json.schemastore.org/github-workflow.json": "/.github/workflows/*.yml",
15+
"https://json.schemastore.org/github-action.json": "/.github/actions/**/*.yml"
16+
},
17+
"files.associations": {
18+
"*.mdx": "markdown"
19+
}
20+
}

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
},
6464
"dependencies": {
6565
"@algorandfoundation/algokit-utils": "^6.2.1",
66-
"@algorandfoundation/algorand-typescript": "^0.0.1-alpha.9",
66+
"@algorandfoundation/algorand-typescript": "^0.0.1-alpha.12",
6767
"@algorandfoundation/puya-ts": "^1.0.0-alpha.14",
6868
"algosdk": "^2.9.0",
6969
"elliptic": "^6.5.7",

src/collections/custom-key-map.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Account, internal } from '@algorandfoundation/algorand-typescript'
2-
import { encodingUtil } from '@algorandfoundation/puya-ts'
32
import { DeliberateAny } from '../typescript-helpers'
3+
import { asBytesCls, asUint64Cls } from '../util'
44

55
type Primitive = number | bigint | string | boolean
66
export abstract class CustomKeyMap<TKey, TValue> implements Map<TKey, TValue> {
@@ -25,6 +25,13 @@ export abstract class CustomKeyMap<TKey, TValue> implements Map<TKey, TValue> {
2525
get(key: TKey): TValue | undefined {
2626
return this.#map.get(this.#keySerializer(key))?.[1]
2727
}
28+
getOrFail(key: TKey): TValue {
29+
const value = this.get(key)
30+
if (value === undefined) {
31+
throw internal.errors.internalError('Key not found')
32+
}
33+
return value
34+
}
2835
has(key: TKey): boolean {
2936
return this.#map.has(this.#keySerializer(key))
3037
}
@@ -62,6 +69,18 @@ export class AccountMap<TValue> extends CustomKeyMap<Account, TValue> {
6269
}
6370

6471
private static getAddressStrFromAccount = (acc: Account) => {
65-
return encodingUtil.uint8ArrayToHex(internal.primitives.BytesCls.fromCompat(acc.bytes).asUint8Array())
72+
return asBytesCls(acc.bytes).valueOf()
73+
}
74+
}
75+
76+
export class BytesMap<TValue> extends CustomKeyMap<internal.primitives.StubBytesCompat, TValue> {
77+
constructor() {
78+
super((bytes) => asBytesCls(bytes).valueOf())
79+
}
80+
}
81+
82+
export class Uint64Map<TValue> extends CustomKeyMap<internal.primitives.StubUint64Compat, TValue> {
83+
constructor() {
84+
super((uint64) => asUint64Cls(uint64).valueOf())
6685
}
6786
}

src/context-helpers/internal-context.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,7 @@ class InternalContext {
6161
}
6262

6363
getApplicationData(id: internal.primitives.StubUint64Compat): ApplicationData {
64-
const key = internal.primitives.Uint64Cls.fromCompat(id)
65-
const data = this.ledger.applicationDataMap.get(key.asBigInt())
64+
const data = this.ledger.applicationDataMap.get(id)
6665
if (!data) {
6766
throw internal.errors.internalError('Unknown application, check correct testing context is active')
6867
}

src/impl/account.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Account, Application, Asset, bytes, internal, uint64 } from '@algorandfoundation/algorand-typescript'
2+
import { Uint64Map } from '../collections/custom-key-map'
23
import { DEFAULT_ACCOUNT_MIN_BALANCE, ZERO_ADDRESS } from '../constants'
34
import { lazyContext } from '../context-helpers/internal-context'
45
import { Mutable } from '../typescript-helpers'
@@ -17,8 +18,8 @@ export class AssetHolding {
1718
}
1819

1920
export class AccountData {
20-
optedAssets = new Map<bigint, AssetHolding>()
21-
optedApplications = new Map<bigint, Application>()
21+
optedAssets = new Uint64Map<AssetHolding>()
22+
optedApplications = new Uint64Map<Application>()
2223
account: Mutable<Omit<Account, 'bytes' | 'isOptedIn'>>
2324

2425
constructor() {
@@ -91,7 +92,7 @@ export class AccountCls extends BytesBackedCls implements Account {
9192

9293
isOptedIn(assetOrApp: Asset | Application): boolean {
9394
if (assetOrApp instanceof AssetCls) {
94-
return this.data.optedAssets.has(asUint64Cls(assetOrApp.id).asBigInt())
95+
return this.data.optedAssets.has(assetOrApp.id)
9596
}
9697
if (assetOrApp instanceof ApplicationCls) {
9798
return this.data.optedApplications.has(asUint64Cls(assetOrApp.id).asBigInt())

src/impl/acct-params.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,51 +22,51 @@ export const minBalance = (a: Account | internal.primitives.StubUint64Compat): u
2222
}
2323

2424
export const AcctParams: internal.opTypes.AcctParamsType = {
25-
acctBalance: function (a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
25+
acctBalance(a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
2626
const acct = getAccount(a)
2727
return [acct.balance, acct.balance !== 0]
2828
},
29-
acctMinBalance: function (a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
29+
acctMinBalance(a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
3030
const acct = getAccount(a)
3131
return [acct.minBalance, acct.balance !== 0]
3232
},
33-
acctAuthAddr: function (a: Account | internal.primitives.StubUint64Compat): readonly [Account, boolean] {
33+
acctAuthAddr(a: Account | internal.primitives.StubUint64Compat): readonly [Account, boolean] {
3434
const acct = getAccount(a)
3535
return [acct.authAddress, acct.balance !== 0]
3636
},
37-
acctTotalNumUint: function (a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
37+
acctTotalNumUint(a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
3838
const acct = getAccount(a)
3939
return [acct.totalNumUint, acct.balance !== 0]
4040
},
41-
acctTotalNumByteSlice: function (a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
41+
acctTotalNumByteSlice(a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
4242
const acct = getAccount(a)
4343
return [acct.totalNumByteSlice, acct.balance !== 0]
4444
},
45-
acctTotalExtraAppPages: function (a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
45+
acctTotalExtraAppPages(a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
4646
const acct = getAccount(a)
4747
return [acct.totalExtraAppPages, acct.balance !== 0]
4848
},
49-
acctTotalAppsCreated: function (a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
49+
acctTotalAppsCreated(a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
5050
const acct = getAccount(a)
5151
return [acct.totalAppsCreated, acct.balance !== 0]
5252
},
53-
acctTotalAppsOptedIn: function (a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
53+
acctTotalAppsOptedIn(a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
5454
const acct = getAccount(a)
5555
return [acct.totalAppsOptedIn, acct.balance !== 0]
5656
},
57-
acctTotalAssetsCreated: function (a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
57+
acctTotalAssetsCreated(a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
5858
const acct = getAccount(a)
5959
return [acct.totalAssetsCreated, acct.balance !== 0]
6060
},
61-
acctTotalAssets: function (a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
61+
acctTotalAssets(a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
6262
const acct = getAccount(a)
6363
return [acct.totalAssets, acct.balance !== 0]
6464
},
65-
acctTotalBoxes: function (a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
65+
acctTotalBoxes(a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
6666
const acct = getAccount(a)
6767
return [acct.totalBoxes, acct.balance !== 0]
6868
},
69-
acctTotalBoxBytes: function (a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
69+
acctTotalBoxBytes(a: Account | internal.primitives.StubUint64Compat): readonly [uint64, boolean] {
7070
const acct = getAccount(a)
7171
return [acct.totalBoxBytes, acct.balance !== 0]
7272
},

src/impl/app-global.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { Application, Bytes, bytes, internal, Uint64, uint64 } from '@algorandfoundation/algorand-typescript'
2+
import { lazyContext } from '../context-helpers/internal-context'
3+
import { asBytes } from '../util'
4+
import { getApp } from './app-params'
5+
6+
export const AppGlobal: internal.opTypes.AppGlobalType = {
7+
delete(a: internal.primitives.StubBytesCompat): void {
8+
lazyContext.ledger.setGlobalState(lazyContext.activeApplication, a, undefined)
9+
},
10+
getBytes(a: internal.primitives.StubBytesCompat): bytes {
11+
return this.getExBytes(0, asBytes(a))[0]
12+
},
13+
getUint64(a: internal.primitives.StubBytesCompat): uint64 {
14+
return this.getExUint64(0, asBytes(a))[0]
15+
},
16+
getExBytes(a: Application | internal.primitives.StubUint64Compat, b: internal.primitives.StubBytesCompat): readonly [bytes, boolean] {
17+
const app = getApp(a)
18+
if (app === undefined) {
19+
return [Bytes(), false]
20+
}
21+
const [state, exists] = lazyContext.ledger.getGlobalState(app, b)
22+
if (!exists) {
23+
return [Bytes(), false]
24+
}
25+
return [state!.value as bytes, exists]
26+
},
27+
getExUint64(a: Application | internal.primitives.StubUint64Compat, b: internal.primitives.StubBytesCompat): readonly [uint64, boolean] {
28+
const app = getApp(a)
29+
if (app === undefined) {
30+
return [Uint64(0), false]
31+
}
32+
const [state, exists] = lazyContext.ledger.getGlobalState(app, b)
33+
if (!exists) {
34+
return [Uint64(0), false]
35+
}
36+
return [state!.value as uint64, exists]
37+
},
38+
put(a: internal.primitives.StubBytesCompat, b: internal.primitives.StubUint64Compat | internal.primitives.StubBytesCompat): void {
39+
lazyContext.ledger.setGlobalState(lazyContext.activeApplication, a, b)
40+
},
41+
}

0 commit comments

Comments
 (0)