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
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
pipx install algokit --python 3.12.6
algokit localnet reset --update
pipx install puyapy --python 3.12.6
node-version: 20.x
node-version: 22.x
run-build: true
run-commit-lint: true
audit-script: npm run audit
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
pipx install algokit
algokit localnet reset --update
pipx install puyapy
node-version: 20.x
node-version: 22.x
run-build: true
run-commit-lint: true
audit-script: npm run audit
Expand All @@ -44,7 +44,7 @@ jobs:
- name: Use Node.js 20.x
uses: actions/setup-node@v4
with:
node-version: 20.x
node-version: 22.x

- run: npm ci --ignore-scripts

Expand Down
10 changes: 5 additions & 5 deletions examples/voting/contract.algo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export class VotingRoundApp extends arc4.Contract {
tallyBox = BoxRef({ key: Bytes`V` })
votesByAccount = BoxMap<Account, VoteIndexArray>({ keyPrefix: Bytes() })
voteId = GlobalState<string>()
snapshotPublicKey = GlobalState<bytes>()
snapshotPublicKey = GlobalState<bytes<32>>()
metadataIpfsCid = GlobalState<string>()
startTime = GlobalState<uint64>()
nftImageUrl = GlobalState<string>()
Expand All @@ -60,7 +60,7 @@ export class VotingRoundApp extends arc4.Contract {
@abimethod({ onCreate: 'require' })
public create(
voteId: string,
snapshotPublicKey: bytes,
snapshotPublicKey: bytes<32>,
metadataIpfsCid: string,
startTime: uint64,
endTime: uint64,
Expand Down Expand Up @@ -158,7 +158,7 @@ export class VotingRoundApp extends arc4.Contract {
}

@abimethod({ readonly: true })
public getPreconditions(signature: bytes): VotingPreconditions {
public getPreconditions(signature: bytes<64>): VotingPreconditions {
return {
is_allowed_to_vote: Uint64(this.allowedToVote(signature)),
is_voting_open: Uint64(this.votingOpen()),
Expand All @@ -167,7 +167,7 @@ export class VotingRoundApp extends arc4.Contract {
}
}

private allowedToVote(signature: bytes): boolean {
private allowedToVote(signature: bytes<64>): boolean {
ensureBudget(2000)
return op.ed25519verifyBare(Txn.sender.bytes, signature, this.snapshotPublicKey.value)
}
Expand All @@ -176,7 +176,7 @@ export class VotingRoundApp extends arc4.Contract {
return this.votesByAccount(Txn.sender).exists
}

public vote(fundMinBalReq: gtxn.PaymentTxn, signature: bytes, answerIds: VoteIndexArray): void {
public vote(fundMinBalReq: gtxn.PaymentTxn, signature: bytes<64>, answerIds: VoteIndexArray): void {
ensureBudget(7700, OpUpFeeSource.GroupCredit)
assert(this.allowedToVote(signature), 'Not allowed to vote')
assert(this.votingOpen(), 'Voting not open')
Expand Down
2 changes: 1 addition & 1 deletion examples/voting/contract.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('VotingRoundApp', () => {

const createContract = () => {
const contract = ctx.contract.create(VotingRoundApp)
const snapshotPublicKey = Bytes(keyPair.publicKey)
const snapshotPublicKey = Bytes(keyPair.publicKey).toFixed({ length: 32 })
const metadataIpfsCid = ctx.any.string(16)
const startTime = ctx.any.uint64(Date.now() - 10_000, Date.now())
const endTime = ctx.any.uint64(Date.now() + 10_000, Date.now() + 100_000)
Expand Down
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@
"vitest": "3.1.3"
},
"dependencies": {
"@algorandfoundation/algorand-typescript": "1.0.0-alpha.59",
"@algorandfoundation/puya-ts": "1.0.0-alpha.59",
"@algorandfoundation/algorand-typescript": "1.0.0-alpha.61",
"@algorandfoundation/puya-ts": "1.0.0-alpha.61",
"elliptic": "^6.6.1",
"js-sha256": "^0.11.0",
"js-sha3": "^0.9.3",
Expand Down
2 changes: 1 addition & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const DEFAULT_GLOBAL_GENESIS_HASH = Bytes(
133, 89, 181, 20, 120, 253, 137, 193, 118, 67, 208, 93, 21, 168, 174, 107, 16, 171, 71, 187, 109, 138, 49, 136, 17, 86, 230, 189, 59,
174, 149, 209,
]),
)
).toFixed({ length: 32 })

// algorand encoded address of 32 zero bytes
export const ZERO_ADDRESS = Bytes.fromBase32('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')
Expand Down
4 changes: 2 additions & 2 deletions src/impl/asset-params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ export const AssetParams: typeof op.AssetParams = {
const asset = getAsset(a)
return asset === undefined ? [Bytes(), false] : [asset.url, true]
},
assetMetadataHash(a: AssetType | StubUint64Compat): readonly [bytes, boolean] {
assetMetadataHash(a: AssetType | StubUint64Compat): readonly [bytes<32>, boolean] {
const asset = getAsset(a)
return asset === undefined ? [Bytes(), false] : [asset.metadataHash, true]
return asset === undefined ? [Bytes() as bytes<32>, false] : [asset.metadataHash, true]
},
assetManager(a: AssetType | StubUint64Compat): readonly [AccountType, boolean] {
const asset = getAsset(a)
Expand Down
12 changes: 6 additions & 6 deletions src/impl/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@ import { Uint64, type StubUint64Compat } from './primitives'
import { Account } from './reference'

export class BlockData {
seed: bytes
seed: bytes<32>
timestamp: uint64
proposer: AccountType
feesCollected: uint64
bonus: uint64
branch: bytes
branch: bytes<32>
feeSink: AccountType
protocol: bytes
txnCounter: uint64
proposerPayout: uint64

constructor() {
this.seed = getRandomBytes(32).asAlgoTs()
this.seed = getRandomBytes(32).asAlgoTs().toFixed({ length: 32 })
this.timestamp = asUint64(Date.now())
this.proposer = Account()
this.feesCollected = Uint64(0)
this.bonus = Uint64(0)
this.branch = getRandomBytes(32).asAlgoTs()
this.branch = getRandomBytes(32).asAlgoTs().toFixed({ length: 32 })
this.feeSink = Account()
this.protocol = getRandomBytes(32).asAlgoTs()
this.txnCounter = Uint64(0)
Expand All @@ -31,7 +31,7 @@ export class BlockData {
}

export const Block: typeof op.Block = {
blkSeed: function (a: StubUint64Compat): bytes {
blkSeed: function (a: StubUint64Compat): bytes<32> {
return lazyContext.ledger.getBlockData(a).seed
},
blkTimestamp: function (a: StubUint64Compat): uint64 {
Expand All @@ -46,7 +46,7 @@ export const Block: typeof op.Block = {
blkBonus: function (a: uint64): uint64 {
return lazyContext.ledger.getBlockData(a).bonus
},
blkBranch: function (a: uint64): bytes {
blkBranch: function (a: uint64): bytes<32> {
return lazyContext.ledger.getBlockData(a).branch
},
blkFeeSink: function (a: uint64): AccountType {
Expand Down
26 changes: 13 additions & 13 deletions src/impl/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,32 @@ import { asBytes, asBytesCls, asUint8Array, conactUint8Arrays } from '../util'
import type { StubBytesCompat, StubUint64Compat } from './primitives'
import { Bytes, BytesCls, Uint64Cls } from './primitives'

export const sha256 = (a: StubBytesCompat): bytes => {
export const sha256 = (a: StubBytesCompat): bytes<32> => {
const bytesA = BytesCls.fromCompat(a)
const hashArray = js_sha256.sha256.create().update(bytesA.asUint8Array()).digest()
const hashBytes = BytesCls.fromCompat(new Uint8Array(hashArray))
return hashBytes.asAlgoTs()
return hashBytes.asAlgoTs().toFixed({ length: 32 })
}

export const sha3_256 = (a: StubBytesCompat): bytes => {
export const sha3_256 = (a: StubBytesCompat): bytes<32> => {
const bytesA = BytesCls.fromCompat(a)
const hashArray = js_sha3.sha3_256.create().update(bytesA.asUint8Array()).digest()
const hashBytes = BytesCls.fromCompat(new Uint8Array(hashArray))
return hashBytes.asAlgoTs()
return hashBytes.asAlgoTs().toFixed({ length: 32 })
}

export const keccak256 = (a: StubBytesCompat): bytes => {
export const keccak256 = (a: StubBytesCompat): bytes<32> => {
const bytesA = BytesCls.fromCompat(a)
const hashArray = js_sha3.keccak256.create().update(bytesA.asUint8Array()).digest()
const hashBytes = BytesCls.fromCompat(new Uint8Array(hashArray))
return hashBytes.asAlgoTs()
return hashBytes.asAlgoTs().toFixed({ length: 32 })
}

export const sha512_256 = (a: StubBytesCompat): bytes => {
export const sha512_256 = (a: StubBytesCompat): bytes<32> => {
const bytesA = BytesCls.fromCompat(a)
const hashArray = js_sha512.sha512_256.create().update(bytesA.asUint8Array()).digest()
const hashBytes = BytesCls.fromCompat(new Uint8Array(hashArray))
return hashBytes.asAlgoTs()
return hashBytes.asAlgoTs().toFixed({ length: 32 })
}

export const ed25519verifyBare = (a: StubBytesCompat, b: StubBytesCompat, c: StubBytesCompat): boolean => {
Expand Down Expand Up @@ -88,7 +88,7 @@ export const ecdsaPkRecover = (
b: StubUint64Compat,
c: StubBytesCompat,
d: StubBytesCompat,
): readonly [bytes, bytes] => {
): readonly [bytes<32>, bytes<32>] => {
if (v !== Ecdsa.Secp256k1) {
throw new InternalError(`Unsupported ECDSA curve: ${v}`)
}
Expand All @@ -106,10 +106,10 @@ export const ecdsaPkRecover = (

const x = pubKey.getX().toArray('be')
const y = pubKey.getY().toArray('be')
return [Bytes(x), Bytes(y)]
return [Bytes(x).toFixed({ length: 32 }), Bytes(y).toFixed({ length: 32 })]
}

export const ecdsaPkDecompress = (v: Ecdsa, a: StubBytesCompat): readonly [bytes, bytes] => {
export const ecdsaPkDecompress = (v: Ecdsa, a: StubBytesCompat): readonly [bytes<32>, bytes<32>] => {
const bytesA = BytesCls.fromCompat(a)

const ecdsa = new elliptic.ec(curveMap[v])
Expand All @@ -118,10 +118,10 @@ export const ecdsaPkDecompress = (v: Ecdsa, a: StubBytesCompat): readonly [bytes

const x = pubKey.getX().toArray('be')
const y = pubKey.getY().toArray('be')
return [Bytes(new Uint8Array(x)), Bytes(new Uint8Array(y))]
return [Bytes(new Uint8Array(x)).toFixed({ length: 32 }), Bytes(new Uint8Array(y)).toFixed({ length: 32 })]
}

export const vrfVerify = (_s: VrfVerify, _a: StubBytesCompat, _b: StubBytesCompat, _c: StubBytesCompat): readonly [bytes, boolean] => {
export const vrfVerify = (_s: VrfVerify, _a: StubBytesCompat, _b: StubBytesCompat, _c: StubBytesCompat): readonly [bytes<64>, boolean] => {
throw new NotImplementedError('vrfVerify')
}

Expand Down
18 changes: 9 additions & 9 deletions src/impl/encoded-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -938,16 +938,16 @@ export class DynamicBytesImpl extends DynamicBytes {
}
}

export class StaticBytesImpl extends StaticBytes {
private value: StaticArrayImpl<ByteImpl, number>
export class StaticBytesImpl<TLength extends uint64 = 0> extends StaticBytes<TLength> {
private value: StaticArrayImpl<ByteImpl, TLength>
typeInfo: TypeInfo

constructor(typeInfo: TypeInfo | string, value?: bytes | string) {
super(value)
constructor(typeInfo: TypeInfo | string, value?: bytes<TLength>) {
super(value ?? (Bytes() as bytes<TLength>))
this.typeInfo = typeof typeInfo === 'string' ? JSON.parse(typeInfo) : typeInfo
const uint8ArrayValue = asUint8Array(value ?? new Uint8Array(StaticBytesImpl.getMaxBytesLength(this.typeInfo)))
this.value = StaticArrayImpl.fromBytesImpl(uint8ArrayValue, typeInfo) as StaticArrayImpl<ByteImpl, number>
return new Proxy(this, arrayProxyHandler<ByteImpl>()) as StaticBytesImpl
this.value = StaticArrayImpl.fromBytesImpl(uint8ArrayValue, typeInfo) as StaticArrayImpl<ByteImpl, TLength>
return new Proxy(this, arrayProxyHandler<ByteImpl>()) as StaticBytesImpl<TLength>
}

get bytes(): bytes {
Expand All @@ -965,8 +965,8 @@ export class StaticBytesImpl extends StaticBytes {
return this.value.length
}

get native(): bytes {
return this.value.bytes
get native(): bytes<TLength> {
return this.value.bytes as bytes<TLength>
}

get items(): ByteImpl[] {
Expand Down Expand Up @@ -994,7 +994,7 @@ export class StaticBytesImpl extends StaticBytes {
static fromBytesImpl(value: StubBytesCompat | Uint8Array, typeInfo: string | TypeInfo, prefix: 'none' | 'log' = 'none'): StaticBytesImpl {
const staticArrayValue = StaticArrayImpl.fromBytesImpl(value, typeInfo, prefix) as StaticArrayImpl<ByteImpl, number>
const result = new StaticBytesImpl(typeInfo)
result.value = staticArrayValue
result.value = staticArrayValue as StaticArrayImpl<ByteImpl, 0>
return result
}

Expand Down
8 changes: 4 additions & 4 deletions src/impl/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ export class GlobalData {
logicSigVersion?: uint64
round?: uint64
latestTimestamp?: uint64
groupId?: bytes
groupId?: bytes<32>
callerApplicationId: uint64
assetCreateMinBalance: uint64
assetOptInMinBalance: uint64
genesisHash: bytes
genesisHash: bytes<32>
opcodeBudget?: uint64
payoutsEnabled: boolean
payoutsGoOnlineFee: uint64
Expand Down Expand Up @@ -146,7 +146,7 @@ export const Global: typeof op.Global = {
/**
* ID of the transaction group. 32 zero bytes if the transaction is not part of a group.
*/
get groupId(): bytes {
get groupId(): bytes<32> {
const data = getGlobalData()
if (data.groupId !== undefined) return data.groupId
const reference = getObjectReference(lazyContext.activeGroup)
Expand Down Expand Up @@ -194,7 +194,7 @@ export const Global: typeof op.Global = {
/**
* The Genesis Hash for the network.
*/
get genesisHash(): bytes {
get genesisHash(): bytes<32> {
return getGlobalData().genesisHash
},

Expand Down
10 changes: 5 additions & 5 deletions src/impl/gtxn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const GTxn: typeof op.GTxn = {
note(t: StubUint64Compat): bytes {
return lazyContext.activeGroup.getTransaction(t).note
},
lease(t: StubUint64Compat): bytes {
lease(t: StubUint64Compat): bytes<32> {
return lazyContext.activeGroup.getTransaction(t).lease
},
receiver(t: StubUint64Compat): Account {
Expand All @@ -34,10 +34,10 @@ export const GTxn: typeof op.GTxn = {
closeRemainderTo(t: StubUint64Compat): Account {
return lazyContext.activeGroup.getPaymentTransaction(t).closeRemainderTo
},
votePk(t: StubUint64Compat): bytes {
votePk(t: StubUint64Compat): bytes<32> {
return lazyContext.activeGroup.getKeyRegistrationTransaction(t).voteKey
},
selectionPk(t: StubUint64Compat): bytes {
selectionPk(t: StubUint64Compat): bytes<32> {
return lazyContext.activeGroup.getKeyRegistrationTransaction(t).selectionKey
},
voteFirst(t: StubUint64Compat): uint64 {
Expand Down Expand Up @@ -73,7 +73,7 @@ export const GTxn: typeof op.GTxn = {
groupIndex(t: StubUint64Compat): uint64 {
return lazyContext.activeGroup.getTransaction(t).groupIndex
},
txId(t: StubUint64Compat): bytes {
txId(t: StubUint64Compat): bytes<32> {
return lazyContext.activeGroup.getTransaction(t).txnId
},
applicationId(t: StubUint64Compat): Application {
Expand Down Expand Up @@ -125,7 +125,7 @@ export const GTxn: typeof op.GTxn = {
configAssetUrl(t: StubUint64Compat): bytes {
return lazyContext.activeGroup.getAssetConfigTransaction(t).url
},
configAssetMetadataHash(t: StubUint64Compat): bytes {
configAssetMetadataHash(t: StubUint64Compat): bytes<32> {
return lazyContext.activeGroup.getAssetConfigTransaction(t).metadataHash
},
configAssetManager(t: StubUint64Compat): Account {
Expand Down
Loading