diff --git a/src/lib/compiler.ts b/src/lib/compiler.ts index 46f720fbb..d42a0355a 100644 --- a/src/lib/compiler.ts +++ b/src/lib/compiler.ts @@ -3077,6 +3077,12 @@ export default class Compiler { const { type, valueType } = storageProp; const action = type === 'box' && !this.isDynamicType(valueType) ? 'replace' : 'set'; + // Honestly not sure why I needed to add this after b89ddc6c24d6102f9e890a0e76222de7e0ca79b5 (0.67.2) + // But it works... + if (type === 'box' && this.teal[this.currentProgram].at(-1)?.teal.startsWith('replace3')) { + this.teal[this.currentProgram].pop(); + } + this.handleStorageAction({ node, name: storageName!, diff --git a/tests/abi.test.ts b/tests/abi.test.ts index 174a4082c..234d84450 100644 --- a/tests/abi.test.ts +++ b/tests/abi.test.ts @@ -37,9 +37,9 @@ async function runMethod(appClient: ApplicationClient, name: string, methodArgs: let fundAmount = 0; let callType: 'call' | 'optIn' = 'call'; - if (name.includes('Storage') || name.includes('RefAccount')) { + if (name.includes('Storage') || name.includes('RefAccount') || name.includes('InBox')) { fundAmount = 127_400; - callType = 'optIn'; + if (name.includes('Storage') || name.includes('RefAccount')) callType = 'optIn'; } return commonRunMethod({ appClient, boxes, method: name, methodArgs, fundAmount, callType }); } @@ -784,5 +784,11 @@ describe('ABI', function () { expect(await runMethod(appClient, 'plusEqualsObjValue')).toEqual([3n, 5n]); }); + + test('plusEqualsObjValueInBox', async () => { + const { appClient } = await compileAndCreate('plusEqualsObjValueInBox'); + + expect(await runMethod(appClient, 'plusEqualsObjValueInBox')).toEqual([3n, 5n]); + }); }); }); diff --git a/tests/contracts/abi.algo.ts b/tests/contracts/abi.algo.ts index e84a1bcf1..8cbd3fc57 100644 --- a/tests/contracts/abi.algo.ts +++ b/tests/contracts/abi.algo.ts @@ -1252,3 +1252,13 @@ class ABITestPlusEqualsObjValue extends Contract { return a; } } + +class ABITestPlusEqualsObjValueInBox extends Contract { + bMap = BoxMap(); + + plusEqualsObjValueInBox(): { foo: uint64; bar: uint64 } { + this.bMap('bMap').value = { foo: 3, bar: 4 }; + this.bMap('bMap').value.bar += 1; + return this.bMap('bMap').value; + } +} diff --git a/tests/contracts/artifacts/ABITestPlusEqualsObjValueInBox.approval.teal b/tests/contracts/artifacts/ABITestPlusEqualsObjValueInBox.approval.teal new file mode 100644 index 000000000..6050696d2 --- /dev/null +++ b/tests/contracts/artifacts/ABITestPlusEqualsObjValueInBox.approval.teal @@ -0,0 +1,82 @@ +#pragma version 9 + +// This TEAL was generated by TEALScript v0.67.2 +// 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 respective branch will be "NOT_IMPLEMENTED" 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 + +abi_route_plusEqualsObjValueInBox: + // The ABI return prefix + byte 0x151f7c75 + + // execute plusEqualsObjValueInBox()(uint64,uint64) + callsub plusEqualsObjValueInBox + concat + log + int 1 + return + +// plusEqualsObjValueInBox()(uint64,uint64) +plusEqualsObjValueInBox: + proto 0 1 + + // tests/contracts/abi.algo.ts:1260 + // this.bMap('bMap').value = { foo: 3, bar: 4 } + byte 0x624d6170 // "bMap" + byte 0x00000000000000030000000000000004 + box_put + + // tests/contracts/abi.algo.ts:1261 + // this.bMap('bMap').value.bar += 1 + int 8 + byte 0x624d6170 // "bMap" + box_get + assert + extract 8 8 + btoi + int 1 + + + itob + byte 0x624d6170 // "bMap" + cover 2 + box_replace + + // tests/contracts/abi.algo.ts:1262 + // return this.bMap('bMap').value; + byte 0x624d6170 // "bMap" + box_get + assert + retsub + +abi_route_createApplication: + int 1 + return + +create_NoOp: + method "createApplication()void" + txna ApplicationArgs 0 + match abi_route_createApplication + err + +call_NoOp: + method "plusEqualsObjValueInBox()(uint64,uint64)" + txna ApplicationArgs 0 + match abi_route_plusEqualsObjValueInBox + err \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestPlusEqualsObjValueInBox.arc32.json b/tests/contracts/artifacts/ABITestPlusEqualsObjValueInBox.arc32.json new file mode 100644 index 000000000..7748f281c --- /dev/null +++ b/tests/contracts/artifacts/ABITestPlusEqualsObjValueInBox.arc32.json @@ -0,0 +1,69 @@ +{ + "hints": { + "plusEqualsObjValueInBox()(uint64,uint64)": { + "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": "I3ByYWdtYSB2ZXJzaW9uIDkKCi8vIFRoaXMgVEVBTCB3YXMgZ2VuZXJhdGVkIGJ5IFRFQUxTY3JpcHQgdjAuNjcuMgovLyBodHRwczovL2dpdGh1Yi5jb20vYWxnb3JhbmRmb3VuZGF0aW9uL1RFQUxTY3JpcHQKCi8vIFRoaXMgY29udHJhY3QgaXMgY29tcGxpYW50IHdpdGggYW5kL29yIGltcGxlbWVudHMgdGhlIGZvbGxvd2luZyBBUkNzOiBbIEFSQzQgXQoKLy8gVGhlIGZvbGxvd2luZyB0ZW4gbGluZXMgb2YgVEVBTCBoYW5kbGUgaW5pdGlhbCBwcm9ncmFtIGZsb3cKLy8gVGhpcyBwYXR0ZXJuIGlzIHVzZWQgdG8gbWFrZSBpdCBlYXN5IGZvciBhbnlvbmUgdG8gcGFyc2UgdGhlIHN0YXJ0IG9mIHRoZSBwcm9ncmFtIGFuZCBkZXRlcm1pbmUgaWYgYSBzcGVjaWZpYyBhY3Rpb24gaXMgYWxsb3dlZAovLyBIZXJlLCBhY3Rpb24gcmVmZXJzIHRvIHRoZSBPbkNvbXBsZXRlIGluIGNvbWJpbmF0aW9uIHdpdGggd2hldGhlciB0aGUgYXBwIGlzIGJlaW5nIGNyZWF0ZWQgb3IgY2FsbGVkCi8vIEV2ZXJ5IHBvc3NpYmxlIGFjdGlvbiBmb3IgdGhpcyBjb250cmFjdCBpcyByZXByZXNlbnRlZCBpbiB0aGUgc3dpdGNoIHN0YXRlbWVudAovLyBJZiB0aGUgYWN0aW9uIGlzIG5vdCBpbXBsbWVudGVkIGluIHRoZSBjb250cmFjdCwgaXRzIHJlc3BlY3RpdmUgYnJhbmNoIHdpbGwgYmUgIk5PVF9JTVBMRU1FTlRFRCIgd2hpY2gganVzdCBjb250YWlucyAiZXJyIgp0eG4gQXBwbGljYXRpb25JRAppbnQgMAo+CmludCA2CioKdHhuIE9uQ29tcGxldGlvbgorCnN3aXRjaCBjcmVhdGVfTm9PcCBOT1RfSU1QTEVNRU5URUQgTk9UX0lNUExFTUVOVEVEIE5PVF9JTVBMRU1FTlRFRCBOT1RfSU1QTEVNRU5URUQgTk9UX0lNUExFTUVOVEVEIGNhbGxfTm9PcAoKTk9UX0lNUExFTUVOVEVEOgoJZXJyCgphYmlfcm91dGVfcGx1c0VxdWFsc09ialZhbHVlSW5Cb3g6CgkvLyBUaGUgQUJJIHJldHVybiBwcmVmaXgKCWJ5dGUgMHgxNTFmN2M3NQoKCS8vIGV4ZWN1dGUgcGx1c0VxdWFsc09ialZhbHVlSW5Cb3goKSh1aW50NjQsdWludDY0KQoJY2FsbHN1YiBwbHVzRXF1YWxzT2JqVmFsdWVJbkJveAoJY29uY2F0Cglsb2cKCWludCAxCglyZXR1cm4KCi8vIHBsdXNFcXVhbHNPYmpWYWx1ZUluQm94KCkodWludDY0LHVpbnQ2NCkKcGx1c0VxdWFsc09ialZhbHVlSW5Cb3g6Cglwcm90byAwIDEKCgkvLyB0ZXN0cy9jb250cmFjdHMvYWJpLmFsZ28udHM6MTI2MAoJLy8gdGhpcy5iTWFwKCdiTWFwJykudmFsdWUgPSB7IGZvbzogMywgYmFyOiA0IH0KCWJ5dGUgMHg2MjRkNjE3MCAvLyAiYk1hcCIKCWJ5dGUgMHgwMDAwMDAwMDAwMDAwMDAzMDAwMDAwMDAwMDAwMDAwNAoJYm94X3B1dAoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czoxMjYxCgkvLyB0aGlzLmJNYXAoJ2JNYXAnKS52YWx1ZS5iYXIgKz0gMQoJaW50IDgKCWJ5dGUgMHg2MjRkNjE3MCAvLyAiYk1hcCIKCWJveF9nZXQKCWFzc2VydAoJZXh0cmFjdCA4IDgKCWJ0b2kKCWludCAxCgkrCglpdG9iCglieXRlIDB4NjI0ZDYxNzAgLy8gImJNYXAiCgljb3ZlciAyCglib3hfcmVwbGFjZQoKCS8vIHRlc3RzL2NvbnRyYWN0cy9hYmkuYWxnby50czoxMjYyCgkvLyByZXR1cm4gdGhpcy5iTWFwKCdiTWFwJykudmFsdWU7CglieXRlIDB4NjI0ZDYxNzAgLy8gImJNYXAiCglib3hfZ2V0Cglhc3NlcnQKCXJldHN1YgoKYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uOgoJaW50IDEKCXJldHVybgoKY3JlYXRlX05vT3A6CgltZXRob2QgImNyZWF0ZUFwcGxpY2F0aW9uKCl2b2lkIgoJdHhuYSBBcHBsaWNhdGlvbkFyZ3MgMAoJbWF0Y2ggYWJpX3JvdXRlX2NyZWF0ZUFwcGxpY2F0aW9uCgllcnIKCmNhbGxfTm9PcDoKCW1ldGhvZCAicGx1c0VxdWFsc09ialZhbHVlSW5Cb3goKSh1aW50NjQsdWludDY0KSIKCXR4bmEgQXBwbGljYXRpb25BcmdzIDAKCW1hdGNoIGFiaV9yb3V0ZV9wbHVzRXF1YWxzT2JqVmFsdWVJbkJveAoJZXJy", + "clear": "I3ByYWdtYSB2ZXJzaW9uIDk=" + }, + "contract": { + "name": "ABITestPlusEqualsObjValueInBox", + "desc": "", + "methods": [ + { + "name": "plusEqualsObjValueInBox", + "args": [], + "desc": "", + "returns": { + "type": "(uint64,uint64)", + "desc": "" + } + }, + { + "name": "createApplication", + "args": [], + "desc": "", + "returns": { + "type": "void", + "desc": "" + } + } + ] + } +} \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestPlusEqualsObjValueInBox.arc4.json b/tests/contracts/artifacts/ABITestPlusEqualsObjValueInBox.arc4.json new file mode 100644 index 000000000..bb118238a --- /dev/null +++ b/tests/contracts/artifacts/ABITestPlusEqualsObjValueInBox.arc4.json @@ -0,0 +1,24 @@ +{ + "name": "ABITestPlusEqualsObjValueInBox", + "desc": "", + "methods": [ + { + "name": "plusEqualsObjValueInBox", + "args": [], + "desc": "", + "returns": { + "type": "(uint64,uint64)", + "desc": "" + } + }, + { + "name": "createApplication", + "args": [], + "desc": "", + "returns": { + "type": "void", + "desc": "" + } + } + ] +} \ No newline at end of file diff --git a/tests/contracts/artifacts/ABITestPlusEqualsObjValueInBox.clear.teal b/tests/contracts/artifacts/ABITestPlusEqualsObjValueInBox.clear.teal new file mode 100644 index 000000000..858e5674c --- /dev/null +++ b/tests/contracts/artifacts/ABITestPlusEqualsObjValueInBox.clear.teal @@ -0,0 +1 @@ +#pragma version 9 \ No newline at end of file