diff --git a/abis/Fixed.json b/abis/Fixed.json new file mode 100644 index 0000000..7bb6973 --- /dev/null +++ b/abis/Fixed.json @@ -0,0 +1,61 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "Fixed", + "sourceName": "contracts/Libraries/Fixed.sol", + "abi": [ + { + "inputs": [ + { + "internalType": "uint256[2]", + "name": "values", + "type": "uint256[2]" + } + ], + "name": "addArray", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "a", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "b", + "type": "uint256" + } + ], + "internalType": "struct Fixed.Struct", + "name": "values", + "type": "tuple" + } + ], + "name": "addStruct", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "pure", + "type": "function" + } + ], + "bytecode": "0x608060405234801561001057600080fd5b506103b8806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806350527d6e1461003b578063e95366181461006b575b600080fd5b61005560048036038101906100509190610223565b61009b565b604051610062919061025f565b60405180910390f35b610085600480360381019061008091906102a1565b6100b8565b604051610092919061025f565b60405180910390f35b6000816020015182600001516100b191906102fd565b9050919050565b6000816001600281106100ce576100cd610353565b5b6020020135826000600281106100e7576100e6610353565b5b60200201356100f691906102fd565b9050919050565b6000604051905090565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61015a82610111565b810181811067ffffffffffffffff8211171561017957610178610122565b5b80604052505050565b600061018c6100fd565b90506101988282610151565b919050565b6000819050919050565b6101b08161019d565b81146101bb57600080fd5b50565b6000813590506101cd816101a7565b92915050565b6000604082840312156101e9576101e861010c565b5b6101f36040610182565b90506000610203848285016101be565b6000830152506020610217848285016101be565b60208301525092915050565b60006040828403121561023957610238610107565b5b6000610247848285016101d3565b91505092915050565b6102598161019d565b82525050565b60006020820190506102746000830184610250565b92915050565b600080fd5b60008190508260206002028201111561029b5761029a61027a565b5b92915050565b6000604082840312156102b7576102b6610107565b5b60006102c58482850161027f565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006103088261019d565b91506103138361019d565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115610348576103476102ce565b5b828201905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea2646970667358221220e9425b7699f274511c172cfff65a57757fc759403c2556e04fe8696671262d4a64736f6c634300080b0033", + "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100365760003560e01c806350527d6e1461003b578063e95366181461006b575b600080fd5b61005560048036038101906100509190610223565b61009b565b604051610062919061025f565b60405180910390f35b610085600480360381019061008091906102a1565b6100b8565b604051610092919061025f565b60405180910390f35b6000816020015182600001516100b191906102fd565b9050919050565b6000816001600281106100ce576100cd610353565b5b6020020135826000600281106100e7576100e6610353565b5b60200201356100f691906102fd565b9050919050565b6000604051905090565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61015a82610111565b810181811067ffffffffffffffff8211171561017957610178610122565b5b80604052505050565b600061018c6100fd565b90506101988282610151565b919050565b6000819050919050565b6101b08161019d565b81146101bb57600080fd5b50565b6000813590506101cd816101a7565b92915050565b6000604082840312156101e9576101e861010c565b5b6101f36040610182565b90506000610203848285016101be565b6000830152506020610217848285016101be565b60208301525092915050565b60006040828403121561023957610238610107565b5b6000610247848285016101d3565b91505092915050565b6102598161019d565b82525050565b60006020820190506102746000830184610250565b92915050565b600080fd5b60008190508260206002028201111561029b5761029a61027a565b5b92915050565b6000604082840312156102b7576102b6610107565b5b60006102c58482850161027f565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006103088261019d565b91506103138361019d565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115610348576103476102ce565b5b828201905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea2646970667358221220e9425b7699f274511c172cfff65a57757fc759403c2556e04fe8696671262d4a64736f6c634300080b0033", + "linkReferences": {}, + "deployedLinkReferences": {} +} diff --git a/src/planner.ts b/src/planner.ts index 1ade750..55857be 100644 --- a/src/planner.ts +++ b/src/planner.ts @@ -30,6 +30,26 @@ class LiteralValue implements Value { } } +class ArrayValue implements Value { + readonly param: ParamType; + readonly values: Value[]; + + constructor(param: ParamType, values: Value[]) { + this.param = param; + this.values = values; + } +} + +class TupleValue implements Value { + readonly param: ParamType; + readonly values: Value[]; + + constructor(param: ParamType, values: any) { + this.param = param; + this.values = values; + } +} + class ReturnValue implements Value { readonly param: ParamType; readonly command: Command; // Function call we want the return value of @@ -75,9 +95,9 @@ export enum CommandFlags { /** A bitmask that selects calltype flags */ CALLTYPE_MASK = 0x03, /** Specifies that this is an extended command, with an additional command word for indices. Internal use only. */ - EXTENDED_COMMAND = 0x40, + EXTENDED_COMMAND = 0x80, /** Specifies that the return value of this call should be wrapped in a `bytes`. Internal use only. */ - TUPLE_RETURN = 0x80, + TUPLE_RETURN = 0x40, } /** @@ -172,10 +192,31 @@ export type ContractFunction = (...args: Array) => FunctionCall; function isDynamicType(param?: ParamType): boolean { if (typeof param === 'undefined') return false; - - return ['string', 'bytes', 'array', 'tuple'].includes(param.baseType); + switch (param.baseType) { + case 'array': + // Check if array is fixed or dynamic + return param.arrayLength === -1; + case 'bytes': + return true; + case 'string': + return true; + case 'tuple': + // Check if tuple contains dynamic types + for (let i = 0; i < param.components.length; i++) { + if (isDynamicType(param.components[i])) return true; + } + return false; + default: + return false; + } } +/* +function isFixedType(param?: ParamType): boolean { + if (typeof param === 'undefined') return false; + return ['tuple', 'array'].includes(param.baseType) && !isDynamicType(param); +} +*/ function abiEncodeSingle(param: ParamType, value: any): LiteralValue { if (isDynamicType(param)) { return new LiteralValue( @@ -197,6 +238,20 @@ function encodeArg(arg: any, param: ParamType): Value { return arg; } else if (arg instanceof Planner) { return new SubplanValue(arg); + } else if (param.baseType === 'array') { + const values: Value[] = []; + for (let i = 0; i < arg.length; i++) { + values.push(encodeArg(arg[i], param.arrayChildren)); + } + return new ArrayValue(param, values); + } else if (param.baseType === 'tuple') { + const values: Value[] = []; + for (let i = 0; i < param.components.length; i++) { + values.push( + encodeArg(arg[param.components[i].name], param.components[i]) + ); + } + return new TupleValue(param, values); } else { return abiEncodeSingle(param, arg); } @@ -561,6 +616,60 @@ export class Planner { this.commands.push(new Command(call, CommandType.RAWCALL)); } + private setVisibility( + arg: Value, + command: Command, + commandVisibility: Map, + literalVisibility: Map, + seen: Set, + planners: Set + ) { + if (arg instanceof ReturnValue) { + if (!seen.has(arg.command)) { + throw new Error( + `Return value from "${arg.command.call.fragment.name}" is not visible here` + ); + } + commandVisibility.set(arg.command, command); + } else if (arg instanceof LiteralValue) { + literalVisibility.set(arg.value, command); + } else if (arg instanceof ArrayValue || arg instanceof TupleValue) { + if (arg instanceof ArrayValue && isDynamicType(arg.param)) { + literalVisibility.set( + defaultAbiCoder.encode(['uint256'], [arg.values.length]), + command + ); + } + for (let i = 0; i < arg.values.length; i++) { + this.setVisibility( + arg.values[i], + command, + commandVisibility, + literalVisibility, + seen, + planners + ); + } + } else if (arg instanceof SubplanValue) { + let subplanSeen = seen; + if ( + !command.call.fragment.outputs || + command.call.fragment.outputs.length === 0 + ) { + // Read-only subplan; return values aren't visible externally + subplanSeen = new Set(seen); + } + arg.planner.preplan( + commandVisibility, + literalVisibility, + subplanSeen, + planners + ); + } else if (!(arg instanceof StateValue)) { + throw new Error(`Unknown function argument type '${typeof arg}'`); + } + } + private preplan( commandVisibility: Map, literalVisibility: Map, @@ -592,34 +701,24 @@ export class Planner { inargs = [command.call.callvalue].concat(inargs); } + // Set pointers total in state + const pointers = this.getPointers(inargs); + if (pointers > 0) { + literalVisibility.set( + defaultAbiCoder.encode(['uint256'], [pointers]), + command + ); + } + for (let arg of inargs) { - if (arg instanceof ReturnValue) { - if (!seen.has(arg.command)) { - throw new Error( - `Return value from "${arg.command.call.fragment.name}" is not visible here` - ); - } - commandVisibility.set(arg.command, command); - } else if (arg instanceof LiteralValue) { - literalVisibility.set(arg.value, command); - } else if (arg instanceof SubplanValue) { - let subplanSeen = seen; - if ( - !command.call.fragment.outputs || - command.call.fragment.outputs.length === 0 - ) { - // Read-only subplan; return values aren't visible externally - subplanSeen = new Set(seen); - } - arg.planner.preplan( - commandVisibility, - literalVisibility, - subplanSeen, - planners - ); - } else if (!(arg instanceof StateValue)) { - throw new Error(`Unknown function argument type '${typeof arg}'`); - } + this.setVisibility( + arg, + command, + commandVisibility, + literalVisibility, + seen, + planners + ); } seen.add(command); } @@ -627,26 +726,49 @@ export class Planner { return { commandVisibility, literalVisibility }; } - private buildCommandArgs( - command: Command, + private getPointers(args: Value[]): number { + let count = 0; + for (let arg of args) { + if (arg instanceof ArrayValue || arg instanceof TupleValue) { + // Tuples can be composed of other tuples or arrays + if (isDynamicType(arg.param)) { + count++; + } + } + } + return count; + } + + private getSlots( + arg: Value, returnSlotMap: Map, literalSlotMap: Map, state: Array ): Array { - // Build a list of argument value indexes - let inargs = command.call.args; - if ( - (command.call.flags & CommandFlags.CALLTYPE_MASK) === - CommandFlags.CALL_WITH_VALUE - ) { - if (!command.call.callvalue) { - throw new Error('Call with value must have a value parameter'); + const slots = new Array(); + if (arg instanceof ArrayValue || arg instanceof TupleValue) { + // Dynamic arrays have a length value + if (arg instanceof ArrayValue && isDynamicType(arg.param)) { + const slot: number = literalSlotMap.get( + defaultAbiCoder.encode(['uint256'], [arg.values.length]) + ) as number; + slots.push(slot); } - inargs = [command.call.callvalue].concat(inargs); - } - - const args = new Array(); - inargs.forEach((arg) => { + // Tuples/arrays can be composed of other tuples or arrays + for (let i = 0; i < arg.values.length; i++) { + const subSlots = this.getSlots( + arg.values[i], + returnSlotMap, + literalSlotMap, + state + ); + slots.push(...subSlots); + } + if (isDynamicType(arg.param)) { + // add pointer flag after slots + slots.push(0xfc); + } + } else { let slot: number; if (arg instanceof ReturnValue) { slot = returnSlotMap.get(arg.command) as number; @@ -663,9 +785,46 @@ export class Planner { if (isDynamicType(arg.param)) { slot |= 0x80; } - args.push(slot); - }); + slots.push(slot); + } + return slots; + } + private buildCommandArgs( + command: Command, + returnSlotMap: Map, + literalSlotMap: Map, + state: Array + ): Array { + // Build a list of argument value indexes + let inargs = command.call.args; + if ( + (command.call.flags & CommandFlags.CALLTYPE_MASK) === + CommandFlags.CALL_WITH_VALUE + ) { + if (!command.call.callvalue) { + throw new Error('Call with value must have a value parameter'); + } + inargs = [command.call.callvalue].concat(inargs); + } + + const args = new Array(); + // Set pointers total in state + const pointers = this.getPointers(inargs); + let slot: number; + if (pointers > 0) { + slot = literalSlotMap.get( + defaultAbiCoder.encode(['uint256'], [pointers]) + ) as number; + } else { + // If no pointers, add IDX_NO_OFFSET flag + slot = 0xfd; + } + args.push(slot); + inargs.forEach((arg) => { + const slots = this.getSlots(arg, returnSlotMap, literalSlotMap, state); + args.push(...slots); + }); return args; } @@ -698,7 +857,6 @@ export class Planner { ps.literalSlotMap, ps.state ); - if (args.length > 6) { flags |= CommandFlags.EXTENDED_COMMAND; } diff --git a/tests/test_planner.ts b/tests/test_planner.ts index 577fa9a..53b466f 100644 --- a/tests/test_planner.ts +++ b/tests/test_planner.ts @@ -5,6 +5,7 @@ import { defaultAbiCoder } from '@ethersproject/abi'; import { CommandFlags, Contract, Planner } from '../src/planner'; import * as mathABI from '../abis/Math.json'; import * as stringsABI from '../abis/Strings.json'; +import * as fixedABI from '../abis/Fixed.json'; const SAMPLE_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'; @@ -39,6 +40,7 @@ describe('Contract', () => { describe('Planner', () => { let Math: Contract; let Strings: Contract; + let Fixed: Contract; before(() => { Math = Contract.createLibrary( @@ -47,6 +49,9 @@ describe('Planner', () => { Strings = Contract.createLibrary( new ethers.Contract(SAMPLE_ADDRESS, stringsABI.abi) ); + Fixed = Contract.createLibrary( + new ethers.Contract(SAMPLE_ADDRESS, fixedABI.abi) + ); }); it('adds function calls to a list of commands', () => { @@ -65,7 +70,37 @@ describe('Planner', () => { expect(commands.length).to.equal(1); expect(commands[0]).to.equal( - '0x771602f7000001ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0x771602f700fd0001ffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + ); + + expect(state.length).to.equal(2); + expect(state[0]).to.equal(defaultAbiCoder.encode(['uint'], [1])); + expect(state[1]).to.equal(defaultAbiCoder.encode(['uint'], [2])); + }); + + it('plans a simple program using fixed-size tuple', () => { + const planner = new Planner(); + planner.add(Fixed.addStruct({ a: 1, b: 2 })); + const { commands, state } = planner.plan(); + + expect(commands.length).to.equal(1); + expect(commands[0]).to.equal( + '0x50527d6e00fd0001ffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + ); + + expect(state.length).to.equal(2); + expect(state[0]).to.equal(defaultAbiCoder.encode(['uint'], [1])); + expect(state[1]).to.equal(defaultAbiCoder.encode(['uint'], [2])); + }); + + it('plans a simple program using fixed-size array', () => { + const planner = new Planner(); + planner.add(Fixed.addArray([1, 2])); + const { commands, state } = planner.plan(); + + expect(commands.length).to.equal(1); + expect(commands[0]).to.equal( + '0xe953661800fd0001ffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); expect(state.length).to.equal(2); @@ -84,15 +119,15 @@ describe('Planner', () => { it('plans a program that uses return values', () => { const planner = new Planner(); const sum1 = planner.add(Math.add(1, 2)); - planner.add(Math.add(sum1, 3)); + planner.add(Fixed.addArray([sum1, 3])); const { commands, state } = planner.plan(); expect(commands.length).to.equal(2); expect(commands[0]).to.equal( - '0x771602f7000001ffffffff01eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0x771602f700fd0001ffffff01eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); expect(commands[1]).to.equal( - '0x771602f7000102ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0xe953661800fd0102ffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); expect(state.length).to.equal(3); @@ -109,10 +144,10 @@ describe('Planner', () => { expect(commands.length).to.equal(2); expect(commands[0]).to.equal( - '0x771602f7000000ffffffff01eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0x771602f700fd0000ffffff01eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); expect(commands[1]).to.equal( - '0x771602f7000001ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0x771602f700fd0001ffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); expect(state.length).to.equal(2); @@ -127,7 +162,7 @@ describe('Planner', () => { expect(commands.length).to.equal(1); expect(commands[0]).to.equal( - '0x367bbd780080ffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0x367bbd7800fd80ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); expect(state.length).to.equal(1); @@ -143,7 +178,7 @@ describe('Planner', () => { expect(commands.length).to.equal(1); expect(commands[0]).to.equal( - '0xd824ccf3008081ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0xd824ccf300fd8081ffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); expect(state.length).to.equal(2); @@ -163,10 +198,10 @@ describe('Planner', () => { expect(commands.length).to.equal(2); expect(commands[0]).to.equal( - '0xd824ccf3008081ffffffff81eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0xd824ccf300fd8081ffffff81eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); expect(commands[1]).to.equal( - '0x367bbd780081ffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0x367bbd7800fd81ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); expect(state.length).to.equal(2); @@ -196,7 +231,7 @@ describe('Planner', () => { expect(commands.length).to.equal(1); expect(commands[0]).to.equal( - '0x08f389c800fefffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0x08f389c800fdfefffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); expect(state.length).to.equal(0); @@ -224,7 +259,7 @@ describe('Planner', () => { const { commands, state } = planner.plan(); expect(commands).to.deep.equal([ - '0xde792d5f0082fefffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + '0xde792d5f00fd82fefffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', ]); expect(state.length).to.equal(3); @@ -238,7 +273,7 @@ describe('Planner', () => { ]) )[0]; expect(subcommands).to.deep.equal([ - '0x771602f7000001ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + '0x771602f700fd0001ffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', ]); }); @@ -253,9 +288,9 @@ describe('Planner', () => { const { commands } = planner.plan(); expect(commands).to.deep.equal([ // Invoke subplanner - '0xde792d5f0083fefffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + '0xde792d5f00fd83fefffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', // sum + 3 - '0x771602f7000102ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + '0x771602f700fd0102ffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', ]); }); @@ -277,9 +312,9 @@ describe('Planner', () => { const { commands, state } = planner.plan(); expect(commands).to.deep.equal([ // Invoke subplanner1 - '0xde792d5f0083fefffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + '0xde792d5f00fd83fefffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', // Invoke subplanner2 - '0xde792d5f0084fefffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + '0xde792d5f00fd84fefffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', ]); expect(state.length).to.equal(5); @@ -292,7 +327,7 @@ describe('Planner', () => { )[0]; expect(subcommands2).to.deep.equal([ // sum + 3 - '0x771602f7000102ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + '0x771602f700fd0102ffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', ]); }); @@ -396,7 +431,7 @@ describe('Planner', () => { const { commands } = planner.plan(); expect(commands).to.deep.equal([ - '0xde792d5f0082feffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + '0xde792d5f00fd82feffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', ]); }); @@ -427,7 +462,7 @@ describe('Planner', () => { expect(commands.length).to.equal(1); expect(commands[0]).to.equal( - '0x771602f7010001ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0x771602f701fd0001ffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); }); @@ -443,7 +478,7 @@ describe('Planner', () => { expect(commands.length).to.equal(1); expect(commands[0]).to.equal( - '0x771602f7020001ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0x771602f702fd0001ffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); }); @@ -458,7 +493,7 @@ describe('Planner', () => { expect(commands.length).to.equal(1); expect(commands[0]).to.equal( - '0x771602f7020001ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0x771602f702fd0001ffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); }); @@ -473,7 +508,7 @@ describe('Planner', () => { const { commands } = planner.plan(); expect(commands.length).to.equal(1); expect(commands[0]).to.equal( - '0xb6b55f25030001ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0xb6b55f2503fd0001ffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); }); @@ -489,8 +524,8 @@ describe('Planner', () => { const { commands } = planner.plan(); expect(commands.length).to.equal(2); expect(commands).to.deep.equal([ - '0x771602f7000001ffffffff01eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', - '0xb6b55f25030102ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + '0x771602f700fd0001ffffff01eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + '0xb6b55f2503fd0102ffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', ]); }); @@ -526,10 +561,10 @@ describe('Planner', () => { const { commands } = planner.plan(); expect(commands.length).to.equal(2); expect(commands[0]).to.equal( - '0xe473580d40000000000000ffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' + '0xe473580d80000000000000ffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' ); expect(commands[1]).to.equal( - '0x00010203040506ffffffffffffffffffffffffffffffffffffffffffffffffff' + '0xfd00010203040506ffffffffffffffffffffffffffffffffffffffffffffffff' ); }); @@ -546,8 +581,8 @@ describe('Planner', () => { planner.add(Test.acceptsBytes(ret)); const { commands } = planner.plan(); expect(commands).to.deep.equal([ - '0x61a7e05e80ffffffffffff80eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', - '0x3e9ef66a0080ffffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + '0x61a7e05e40fdffffffffff80eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', + '0x3e9ef66a00fd80ffffffffffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', ]); }); });