Skip to content

Commit

Permalink
Making it possible to specify contract by hash and name.
Browse files Browse the repository at this point in the history
  • Loading branch information
Jakub Zajkowski committed Jul 18, 2024
1 parent 2ef6cbe commit a2d8b7f
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 67 deletions.
20 changes: 4 additions & 16 deletions e2e/services/CasperServiceByJsonRPC.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,7 @@ import {
TransactionCategoryMint,
makeV1Transaction
} from '../../src/lib/TransactionUtil';
import {
Native,
Session,
Stored,
TransactionSessionKind
} from '../../src/lib/TransactionTarget';
import { Native, Session, Stored } from '../../src/lib/TransactionTarget';
import { Call, Custom, Transfer } from '../../src/lib/TransactionEntryPoint';
import { Standard } from '../../src/lib/TransactionScheduling';
import { InitiatorAddr } from '../../src/lib/InitiatorAddr';
Expand Down Expand Up @@ -460,7 +455,6 @@ describe('CasperServiceByJsonRPC', () => {
assert.exists(contractHash);

cep18.setContractHash(contractHash!);
cep18.setContractName(`cep18_contract_hash_${tokenName}`);
const fetchedTokenName = await cep18.queryContractData(['name']);
const fetchedTokenSymbol = await cep18.queryContractData(['symbol']);
const fetchedTokenDecimals: BigNumber = await cep18.queryContractData([
Expand Down Expand Up @@ -512,7 +506,7 @@ describe('CasperServiceByJsonRPC', () => {
result = await client.waitForDeploy(transferDeploy, 100000);

assert.equal(result.deploy.hash, deploy_hash);
expect(result.deploy.session).to.have.property('StoredContractByName');
expect(result.deploy.session).to.have.property('StoredContractByHash');
expect(result.execution_info!.execution_result!).to.have.property(
'Version2'
);
Expand All @@ -526,7 +520,7 @@ describe('CasperServiceByJsonRPC', () => {
});

//This needs to wait for a fix in the node which currently prevents wasm transactions
xit('CEP18 should work deployed via "account_put_transaction"', async () => {
it('CEP18 should work deployed via "account_put_transaction"', async () => {
const casperClient = new CasperClient(NODE_URL);
const cep18 = new Contract(casperClient);
const wasmPath = path.resolve(__dirname, './cep18.wasm');
Expand Down Expand Up @@ -556,18 +550,13 @@ describe('CasperServiceByJsonRPC', () => {
const transaction = makeV1Transaction(
params,
runtimeArgs,
Session.build(
TransactionSessionKind.Installer,
wasm,
TransactionRuntime.VmCasperV1
),
Session.build(wasm, TransactionRuntime.VmCasperV1),
new Call(),
new Standard(),
TransactionCategoryInstallUpgrade
);
const signedTransaction = transaction.sign([faucetKey]);
await client.transaction(signedTransaction);

await sleep(2500);

const result = await client.waitForTransaction(signedTransaction, 100000);
Expand All @@ -585,7 +574,6 @@ describe('CasperServiceByJsonRPC', () => {
assert.exists(contractHash);

cep18.setContractHash(contractHash!);
cep18.setContractName(`cep18_contract_hash_${tokenName}`);
const fetchedTokenName = await cep18.queryContractData(['name']);
const fetchedTokenSymbol = await cep18.queryContractData(['symbol']);
const fetchedTokenDecimals: BigNumber = await cep18.queryContractData([
Expand Down
41 changes: 33 additions & 8 deletions src/lib/Contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export const contractHashToByteArray = (contractHash: string) =>
const NO_CLIENT_ERR =
'You need to either create Contract instance with casperClient or pass it as parameter to this function';

const NO_ENTRYPOINT_QUALIFIER =
'You need to either specify contractName or contractHash before calling an endpoint';

/** Smart contract object for interacting with contracts on the Casper Network */
export class Contract {
public contractHash?: string;
Expand Down Expand Up @@ -86,8 +89,10 @@ export class Contract {
}

private checkSetup(): boolean {
if (this.contractHash) return true;
throw Error('You need to setContract before running this method.');
if (this.contractHash || this.contractName) return true;
throw Error(
'You need to setContractHash or setContractName before running this method.'
);
}

/**
Expand All @@ -111,14 +116,10 @@ export class Contract {
ttl: number = DEFAULT_DEPLOY_TTL
): Deploy {
this.checkSetup();

const session = this.buildSession(entryPoint, args);
const deploy = DeployUtil.makeDeploy(
new DeployUtil.DeployParams(sender, chainName, 1, ttl),
DeployUtil.ExecutableDeployItem.newStoredContractByName(
this.contractName!,
entryPoint,
args
),
session,
DeployUtil.standardPayment(paymentAmount)
);

Expand Down Expand Up @@ -192,6 +193,30 @@ export class Contract {
throw Error('Invalid stored value');
}
}

private buildSession(
entryPoint: string,
args: RuntimeArgs
): DeployUtil.ExecutableDeployItem {
if (this.contractHash) {
const hashOnly = this.contractHash!.slice(16);
const addrEntityBytes = contractHashToByteArray(hashOnly);

return DeployUtil.ExecutableDeployItem.newStoredContractByHash(
addrEntityBytes,
entryPoint,
args
);
} else if (this.contractName) {
return DeployUtil.ExecutableDeployItem.newStoredContractByName(
this.contractName!,
entryPoint,
args
);
} else {
throw Error(NO_ENTRYPOINT_QUALIFIER);
}
}
}

/**
Expand Down
6 changes: 3 additions & 3 deletions src/lib/DeployUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,8 @@ export class StoredContractByHash extends ExecutableDeployItemInternal {
public args: RuntimeArgs;

/**
* Constructs a `StoredContractByHash` object from the `Uint8Array` typed hash, entrypoint of the contract, and associated runtime arguments
* @param hash `Uint8Array` typed smart contract hash
* Constructs a `StoredContractByHash` object from the hash, entrypoint of the contract, and associated runtime arguments
* @param hash hash of the addressable entity of the contract
* @param entryPoint An entrypoint of the smart contract
* @param args The runtime arguments for interaction on the `entryPoint`
*/
Expand Down Expand Up @@ -748,7 +748,7 @@ export class ExecutableDeployItem implements ToBytes {

/**
* Creates a new `StoredContractByHash` object from a `Uint8Array` contract hash, entrypoint, and runtime arguments
* @param hash `Uint8Array` representation of a smart contract hash
* @param hash `string` representation of a smart contract addreassable entity hash
* @param entryPoint Name of an entrypoint of the stored contract
* @param args The runtime arguments for the new `StoredContractByHash` object
* @returns A new `ExecutableDeployItem` created from a new `StoredContractByHash` object built using `hash`, `entryPoint` and `args`
Expand Down
3 changes: 1 addition & 2 deletions src/lib/TransactionTarget.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,10 @@ const expectedStoredVariantBytes = [
0,
0
];
const expectedSessionVariantBytes = [2, 0, 4, 0, 0, 0, 81, 5, 6, 10, 0];
const expectedSessionVariantBytes = [2, 4, 0, 0, 0, 81, 5, 6, 10, 0];
const mockSessionJson = {
a: {
Session: {
kind: 'Standard',
module_bytes: '5105060a',
runtime: 'VmCasperV1'
}
Expand Down
38 changes: 1 addition & 37 deletions src/lib/TransactionTarget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,36 +71,8 @@ export class Stored implements TransactionTarget {
}
}

/**
* enum of transaction session kind
* @enum
*/
export enum TransactionSessionKind {
Standard = 'Standard',
Installer = 'Installer',
Upgrader = 'Upgrader',
Isolated = 'Isolated'
}

function kindToBytes(sessionKind: TransactionSessionKind): Uint8Array {
switch (sessionKind) {
case TransactionSessionKind.Standard:
return toBytesU8(0);
case TransactionSessionKind.Installer:
return toBytesU8(1);
case TransactionSessionKind.Upgrader:
return toBytesU8(2);
case TransactionSessionKind.Isolated:
return toBytesU8(3);
default:
throw new Error('Unknown session kind');
}
}

@jsonObject
export class Session implements TransactionTarget {
@jsonMember({ constructor: String })
public kind: TransactionSessionKind;
@jsonMember({
name: 'module_bytes',
serializer: byteArrayJsonSerializer,
Expand All @@ -112,15 +84,13 @@ export class Session implements TransactionTarget {
public toJSON(): unknown {
return {
Session: {
kind: this.kind,
module_bytes: byteArrayJsonSerializer(this.moduleBytes),
runtime: this.runtime
}
};
}

public toBytes(): ToBytesResult {
const kindBytes = kindToBytes(this.kind);
const maybeRuntimeBytes = transactionRuntimeToBytes(this.runtime);
if (maybeRuntimeBytes.err) {
return maybeRuntimeBytes;
Expand All @@ -130,19 +100,13 @@ export class Session implements TransactionTarget {
return Ok(
concat([
toBytesU8(SESSION_TAG),
kindBytes,
toBytesArrayU8(this.moduleBytes),
runtimeBytes
])
);
}
static build(
kind: TransactionSessionKind,
moduleBytes: Uint8Array,
runtime: TransactionRuntime
): Session {
static build(moduleBytes: Uint8Array, runtime: TransactionRuntime): Session {
const session = new Session();
session.kind = kind;
session.moduleBytes = moduleBytes;
session.runtime = runtime;
return session;
Expand Down
1 change: 0 additions & 1 deletion src/services/CasperServiceByJsonRPC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,6 @@ export class CasperServiceByJsonRPC {
'This method is deprecated and will be removed in the future release, please use transaction method instead.'
);
this.checkDeploySize(signedDeploy);

const { checkApproval = false } = props ?? {};
if (checkApproval && signedDeploy.approvals.length == 0) {
throw new Error('Required signed deploy');
Expand Down

0 comments on commit a2d8b7f

Please sign in to comment.