Skip to content

Commit 4f47ba5

Browse files
authored
Remove old-style covenants from SDK (#259)
- Remove all old-style covenant functionality and tests - Add semver check with minimum supported cashc version
1 parent 38d9927 commit 4f47ba5

23 files changed

+91
-548
lines changed

packages/cashc/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,12 @@
5353
"@cashscript/utils": "^0.11.0-next.0",
5454
"antlr4": "^4.13.1-patch-1",
5555
"commander": "^7.1.0",
56-
"semver": "^7.5.4"
56+
"semver": "^7.6.3"
5757
},
5858
"devDependencies": {
5959
"@jest/globals": "^29.4.1",
6060
"@types/node": "^18.11.18",
61-
"@types/semver": "^7.3.4",
61+
"@types/semver": "^7.5.8",
6262
"cpy-cli": "^4.2.0",
6363
"eslint": "^8.54.0",
6464
"jest": "^29.4.1",

packages/cashscript/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,14 @@
4949
"delay": "^5.0.0",
5050
"electrum-cash": "^2.0.10",
5151
"fast-deep-equal": "^3.1.3",
52-
"pako": "^2.1.0"
52+
"pako": "^2.1.0",
53+
"semver": "^7.6.3"
5354
},
5455
"devDependencies": {
5556
"@jest/globals": "^29.4.1",
5657
"@psf/bch-js": "^6.8.0",
5758
"@types/pako": "^2.0.3",
59+
"@types/semver": "^7.5.8",
5860
"eslint": "^8.54.0",
5961
"jest": "^29.4.1",
6062
"typescript": "^5.5.4"

packages/cashscript/src/Contract.ts

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
import SignatureTemplate from './SignatureTemplate.js';
2626
import { ElectrumNetworkProvider } from './network/index.js';
2727
import { ParamsToTuple, AbiToFunctionMap } from './types/type-inference.js';
28+
import semver from 'semver';
2829

2930
export class Contract<
3031
TArtifact extends Artifact = Artifact,
@@ -62,11 +63,15 @@ export class Contract<
6263
this.provider = this.options?.provider ?? new ElectrumNetworkProvider();
6364
this.addressType = this.options?.addressType ?? 'p2sh32';
6465

65-
const expectedProperties = ['abi', 'bytecode', 'constructorInputs', 'contractName'];
66+
const expectedProperties = ['abi', 'bytecode', 'constructorInputs', 'contractName', 'compiler'];
6667
if (!expectedProperties.every((property) => property in artifact)) {
6768
throw new Error('Invalid or incomplete artifact provided');
6869
}
6970

71+
if (!semver.satisfies(artifact.compiler.version, '>=0.7.0', { includePrerelease: true })) {
72+
throw new Error(`Artifact compiled with unsupported compiler version: ${artifact.compiler.version}, required >=0.7.0`);
73+
}
74+
7075
if (artifact.constructorInputs.length !== constructorArgs.length) {
7176
throw new Error(`Incorrect number of arguments passed to ${artifact.contractName} constructor. Expected ${artifact.constructorInputs.length} arguments (${artifact.constructorInputs.map((input) => input.type)}) but got ${constructorArgs.length}`);
7277
}
@@ -156,28 +161,16 @@ export class Contract<
156161
const generateUnlockingBytecode = (
157162
{ transaction, sourceOutputs, inputIndex }: GenerateUnlockingBytecodeOptions,
158163
): Uint8Array => {
159-
// TODO: Remove old-style covenant code for v1.0 release
160-
let covenantHashType = -1;
161164
const completeArgs = encodedArgs.map((arg) => {
162165
if (!(arg instanceof SignatureTemplate)) return arg;
163166

164-
// First signature is used for sighash preimage (maybe not the best way)
165-
if (covenantHashType < 0) covenantHashType = arg.getHashType();
166-
167+
// Generate transaction signature from SignatureTemplate
167168
const preimage = createSighashPreimage(transaction, sourceOutputs, inputIndex, bytecode, arg.getHashType());
168169
const sighash = hash256(preimage);
169-
170170
return arg.generateSignature(sighash);
171171
});
172172

173-
const preimage = abiFunction.covenant
174-
? createSighashPreimage(transaction, sourceOutputs, inputIndex, bytecode, covenantHashType)
175-
: undefined;
176-
177-
const unlockingBytecode = createInputScript(
178-
this.redeemScript, completeArgs, selector, preimage,
179-
);
180-
173+
const unlockingBytecode = createInputScript(this.redeemScript, completeArgs, selector);
181174
return unlockingBytecode;
182175
};
183176

packages/cashscript/src/Transaction.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
AbiFunction,
1010
encodeBip68,
1111
placeholder,
12-
scriptToBytecode,
1312
} from '@cashscript/utils';
1413
import deepEqual from 'fast-deep-equal';
1514
import {
@@ -28,7 +27,6 @@ import {
2827
getInputSize,
2928
createOpReturnOutput,
3029
getTxSizeWithoutInputs,
31-
getPreimageSize,
3230
validateOutput,
3331
utxoComparator,
3432
calculateDust,
@@ -61,7 +59,7 @@ export class Transaction {
6159
public abiFunction: AbiFunction,
6260
public encodedFunctionArgs: EncodedFunctionArgument[],
6361
private selector?: number,
64-
) {}
62+
) { }
6563

6664
from(input: Utxo): this;
6765
from(inputs: Utxo[]): this;
@@ -175,10 +173,7 @@ export class Transaction {
175173
const tx = await this.build();
176174

177175
// Debug the transaction locally before sending so any errors are caught early
178-
// Libauth debugging does not work with old-style covenants
179-
if (!this.abiFunction.covenant) {
180-
await this.debug();
181-
}
176+
await this.debug();
182177

183178
try {
184179
const txid = await this.contract.provider.sendRawTransaction(tx);
@@ -350,18 +345,11 @@ export class Transaction {
350345
return placeholder(73);
351346
});
352347

353-
// Create a placeholder preimage of the correct size
354-
const placeholderPreimage = this.abiFunction.covenant
355-
? placeholder(getPreimageSize(scriptToBytecode(this.contract.redeemScript)))
356-
: undefined;
357-
358-
// Create a placeholder input script for size calculation using the placeholder
359-
// arguments and correctly sized placeholder preimage
348+
// Create a placeholder input script for size calculation using the placeholder arguments
360349
const placeholderScript = createInputScript(
361350
this.contract.redeemScript,
362351
placeholderArgs,
363352
this.selector,
364-
placeholderPreimage,
365353
);
366354

367355
// Add one extra byte per input to over-estimate tx-in count

packages/cashscript/src/utils.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {
55
lockingBytecodeToCashAddress,
66
binToHex,
77
Transaction,
8-
generateSigningSerializationBCH,
8+
generateSigningSerializationBch,
99
utf8ToBin,
1010
hexToBin,
1111
flattenBinArray,
@@ -125,12 +125,6 @@ export function getInputSize(inputScript: Uint8Array): number {
125125
return 32 + 4 + varIntSize + scriptSize + 4;
126126
}
127127

128-
export function getPreimageSize(script: Uint8Array): number {
129-
const scriptSize = script.byteLength;
130-
const varIntSize = scriptSize > 252 ? 3 : 1;
131-
return 4 + 32 + 32 + 36 + varIntSize + scriptSize + 8 + 4 + 32 + 4 + 4;
132-
}
133-
134128
export function getTxSizeWithoutInputs(outputs: Output[]): number {
135129
// Transaction format:
136130
// Version (4 Bytes)
@@ -160,11 +154,9 @@ export function createInputScript(
160154
redeemScript: Script,
161155
encodedArgs: Uint8Array[],
162156
selector?: number,
163-
preimage?: Uint8Array,
164157
): Uint8Array {
165-
// Create unlock script / redeemScriptSig (add potential preimage and selector)
158+
// Create unlock script / redeemScriptSig (add potential selector)
166159
const unlockScript = [...encodedArgs].reverse();
167-
if (preimage !== undefined) unlockScript.push(preimage);
168160
if (selector !== undefined) unlockScript.push(encodeInt(BigInt(selector)));
169161

170162
// Create input script and compile it to bytecode
@@ -199,7 +191,7 @@ export function createSighashPreimage(
199191
const context = { inputIndex, sourceOutputs, transaction };
200192
const signingSerializationType = new Uint8Array([hashtype]);
201193

202-
const sighashPreimage = generateSigningSerializationBCH(context, { coveredBytecode, signingSerializationType });
194+
const sighashPreimage = generateSigningSerializationBch(context, { coveredBytecode, signingSerializationType });
203195

204196
return sighashPreimage;
205197
}

packages/cashscript/test/Contract.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import p2pkhArtifact from './fixture/p2pkh.json' with { type: 'json' };
1515
import twtArtifact from './fixture/transfer_with_timeout.json' with { type: 'json' };
1616
import hodlVaultArtifact from './fixture/hodl_vault.json' with { type: 'json' };
1717
import mecenasArtifact from './fixture/mecenas.json' with { type: 'json' };
18+
import deprecatedMecenasArtifact from './fixture/deprecated/mecenas-v0.6.0.json' with { type: 'json' };
1819
import boundedBytesArtifact from './fixture/bounded_bytes.json' with { type: 'json' };
1920

2021
describe('Contract', () => {
@@ -31,6 +32,14 @@ describe('Contract', () => {
3132
expect(() => new Contract(p2pkhArtifact, [placeholder(21)], { provider })).toThrow();
3233
});
3334

35+
it('should fail with artifact compiled with unsupported compiler version', async () => {
36+
const provider = new ElectrumNetworkProvider(Network.CHIPNET);
37+
const constructorArgs = [placeholder(20), placeholder(20), 1000000n];
38+
39+
expect(() => new Contract(deprecatedMecenasArtifact, constructorArgs, { provider }))
40+
.toThrow(/unsupported compiler version/);
41+
});
42+
3443
it('should fail with incomplete artifact', () => {
3544
const provider = new ElectrumNetworkProvider(Network.CHIPNET);
3645

packages/cashscript/test/e2e/old/Mecenas.test.ts

Lines changed: 0 additions & 104 deletions
This file was deleted.

packages/cashscript/test/e2e/old/misc.test.ts

Lines changed: 0 additions & 77 deletions
This file was deleted.

0 commit comments

Comments
 (0)