Skip to content

Commit

Permalink
Add makeCep18TransferDeploy and makeNftTransferDeploy utils
Browse files Browse the repository at this point in the history
  • Loading branch information
Comp0te committed Dec 16, 2024
1 parent b11cb48 commit 9773801
Show file tree
Hide file tree
Showing 7 changed files with 357 additions and 6 deletions.
78 changes: 78 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ npm install casper-js-sdk --save
- [Creating a legacy deploy](#creating-a-legacy-deploy)
- [Creating and sending CSPR transfer deploy](#creating-and-sending-cspr-transfer-deploy)
- [Creating and sending Auction manager deploy](#creating-and-sending-auction-manager-deploy)
- [Creating and sending CEP-18 transfer deploy](#creating-and-sending-cep-18-transfer-deploy)
- [Creating and sending NFT transfer deploy](#creating-and-sending-nft-transfer-deploy)

## Migration guides

Expand Down Expand Up @@ -310,3 +312,79 @@ const result = await rpcClient.putDeploy(deploy);

console.log(`Deploy Hash: ${result.deployHash}`);
```

### Creating and sending CEP-18 transfer deploy

Example of how to construct a CEP-18 transfer deploy and push it to the network:

```ts
import {
HttpHandler,
RpcClient,
KeyAlgorithm,
PrivateKey,
makeCep18TransferDeploy
} from 'casper-js-sdk';

// get private key fromHex, fromPem or generate it
const privateKey = await PrivateKey.fromHex(
'privateKeyHex',
KeyAlgorithm.SECP256K1 // or KeyAlgorithm.ED25519, depends on your private key
);

const deploy = await makeCep18TransferDeploy({
contractHash: '0123456789asdfbcdef...',
senderPublicKeyHex: '0123456789asdfbcdef...',
recipientPublicKeyHex: '0123456789abcdef...',
transferAmount: '25000000000', // 25 CEP-18 with 9 decimals
paymentAmount: '3000000000' // 3 CSPR
});

await deploy.sign(privateKey);

const rpcHandler = new HttpHandler('http://<Node Address>:7777/rpc');
const rpcClient = new RpcClient(rpcHandler);

const result = await rpcClient.putDeploy(deploy);

console.log(`Deploy Hash: ${result.deployHash}`);
```

### Creating and sending NFT transfer deploy

Example of how to construct a NFT transfer deploy and push it to the network:

```ts
import {
HttpHandler,
RpcClient,
KeyAlgorithm,
PrivateKey,
makeNftTransferDeploy,
NFTTokenStandard
} from 'casper-js-sdk';

// get private key fromHex, fromPem or generate it
const privateKey = await PrivateKey.fromHex(
'privateKeyHex',
KeyAlgorithm.SECP256K1 // or KeyAlgorithm.ED25519, depends on your private key
);

const deploy = await makeNftTransferDeploy({
nftStandard: NFTTokenStandard.CEP47,
contractPackageHash: '0123456789asdfbcdef...',
senderPublicKeyHex: '0123456789asdfbcdef...',
recipientPublicKeyHex: '0123456789abcdef...',
paymentAmount: '3000000000', // 3 CSPR
tokenId: 234
});

await deploy.sign(privateKey);

const rpcHandler = new HttpHandler('http://<Node Address>:7777/rpc');
const rpcClient = new RpcClient(rpcHandler);

const result = await rpcClient.putDeploy(deploy);

console.log(`Deploy Hash: ${result.deployHash}`);
```
5 changes: 5 additions & 0 deletions src/@types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,8 @@ export enum AuctionManagerEntryPoint {
undelegate = 'undelegate',
redelegate = 'redelegate'
}

export enum NFTTokenStandard {
CEP47 = 'CEP47',
CEP78 = 'CEP78'
}
9 changes: 6 additions & 3 deletions src/utils/auction-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ export interface IMakeAuctionManagerDeployParams {
}

/**
* Creates a deploy for the Auction Manager contract.
* Creates a `Deploy` for the Auction Manager contract.
*
* This function generates a deploy that interacts with the Auction Manager
* This function generates a `Deploy` that interacts with the Auction Manager
* contract on the Casper network. It supports operations such as delegation,
* un-delegation, and validator change management.
*
* @param params - The parameters required to create the deploy.
* @param params - The parameters required to create the Auction Manager deploy.
* @param params.contractEntryPoint - The entry point to invoke in the Auction Manager contract.
* @param params.delegatorPublicKeyHex - The delegator's public key in hexadecimal format.
* @param params.validatorPublicKeyHex - The validator's public key in hexadecimal format.
Expand All @@ -46,6 +46,9 @@ export interface IMakeAuctionManagerDeployParams {
* @param params.chainName - (Optional) The name of the Casper network chain - {CasperNetworkName}.
* Must be either `'casper'` (mainnet) or `'casper-test'` (testnet).
* Defaults to `'CasperNetworkName.Mainnet'` if not specified.
* @param params.ttl - (Optional) The time-to-live (TTL) for the `Deploy` in milliseconds.
* Specifies how long the `Deploy` is valid before it expires.
* Defaults 1800000 (30 minutes)
*
* @returns A deploy object that can be signed and sent to the network.
*
Expand Down
93 changes: 93 additions & 0 deletions src/utils/cep-18-transfer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import {
Args,
CLValue,
CLValueUInt256,
ContractHash,
DEFAULT_DEPLOY_TTL,
Deploy,
DeployHeader,
Duration,
ExecutableDeployItem, Key, KeyTypeID,
PublicKey,
StoredContractByHash
} from '../types';
import { CasperNetworkName } from '../@types';

export interface IMakeCep18TransferDeployParams {
contractHash: string,
senderPublicKeyHex: string;
recipientPublicKeyHex: string;
transferAmount: string;
paymentAmount: string,
chainName?: CasperNetworkName;
ttl?: number;
}

/**
* This function generates a `Deploy` for transferring CEP-18 from one account to another.
*
* @param params - The parameters required to create the CEP-18 transfer deploy.
* @param params.contractHash - The hash of the contract to interact with.
* This is a 64-character hexadecimal string representing the contract.
* @param params.senderPublicKeyHex - The sender's public key in hexadecimal format.
* @param params.recipientPublicKeyHex - The recipient's public key in hexadecimal format.
* @param params.transferAmount - The amount of CSPR to transfer.
* This value must be represented in its smallest unit (motes).
* For example, to transfer 2.5 CSPR, provide the value `2500000000` (2.5 * 10^9 motes).
* @param params.paymentAmount - The amount of CSPR to pay a network fee.
* This value must be represented in its smallest unit (motes).
* @param params.chainName - (Optional) The name of the Casper network chain - {CasperNetworkName}.
* Must be either `'casper'` (mainnet) or `'casper-test'` (testnet).
* Defaults to `'CasperNetworkName.Mainnet'` if not specified.
* @param params.ttl - (Optional) The time-to-live (TTL) for the `Deploy` in milliseconds.
* Specifies how long the `Deploy` is valid before it expires.
* Defaults 1800000 (30 minutes)
* @returns A promise that resolves to the created Deploy instance, ready to be sent to the Casper network.
*
* @example
* ```ts
* import { makeCsprTransferDeploy } from 'casper-js-sdk';
*
* const deploy = await makeCep18TransferDeploy({
* contractHash: '0123456789asdfbcdef...',
* senderPublicKeyHex: '0123456789asdfbcdef...',
* recipientPublicKeyHex: '0123456789abcdef...',
* transferAmount: '25000000000', // 25 CEP-18 with 9 decimals
* paymentAmount: '3000000000', // 3 CSPR
* });
*
* console.log('Created Deploy:', deploy);
* ```
*/
export const makeCep18TransferDeploy = ({
contractHash,
senderPublicKeyHex,
recipientPublicKeyHex,
transferAmount,
paymentAmount,
chainName = CasperNetworkName.Mainnet,
ttl = DEFAULT_DEPLOY_TTL,
}: IMakeCep18TransferDeployParams): Deploy => {
const senderPublicKey = PublicKey.newPublicKey(senderPublicKeyHex);
const recipientPublicKey = PublicKey.newPublicKey(recipientPublicKeyHex);

const session = new ExecutableDeployItem();

session.storedContractByHash = new StoredContractByHash(
ContractHash.newContract(contractHash),
'transfer',
Args.fromMap({
recipient: CLValue.newCLKey(Key.createByType(recipientPublicKey.accountHash().toPrefixedString(), KeyTypeID.Account)),
amount: CLValueUInt256.newCLUInt256(transferAmount)
})
);

const payment = ExecutableDeployItem.standardPayment(paymentAmount);

const deployHeader = DeployHeader.default();
deployHeader.account = senderPublicKey;
deployHeader.chainName = chainName;
deployHeader.ttl = new Duration(ttl);

return Deploy.makeDeploy(deployHeader, payment, session);
};
168 changes: 168 additions & 0 deletions src/utils/cep-nft-transfer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import {
Args,
CLTypeUInt256,
CLValue,
CLValueBool,
CLValueList,
CLValueUInt256,
CLValueUInt64,
ContractHash,
DEFAULT_DEPLOY_TTL,
Deploy,
DeployHeader,
Duration,
ExecutableDeployItem, Key, KeyTypeID,
PublicKey,
StoredVersionedContractByHash
} from '../types';
import { CasperNetworkName, NFTTokenStandard } from '../@types';

export interface IMakeNftTransferDeployParams {
nftStandard: NFTTokenStandard;
contractPackageHash: string;
senderPublicKeyHex: string;
recipientPublicKeyHex: string;
paymentAmount: string;
chainName?: CasperNetworkName;
ttl?: number;
tokenId?: string;
tokenHash?: string;
}

/**
* Creates a `Deploy` for transferring an NFT (Non-Fungible Token).
* This function constructs and returns a `Deploy` for transferring NFTs according to the specified parameters.
*
* @param params - The parameters required to create the NFT transfer deploy.
* @param params.nftStandard - The NFT standard being used (e.g., CEP-78, CEP-47).
* @param params.contractPackageHash - The hash of the contract package to interact with.
* @param params.senderPublicKeyHex - The sender's public key in hexadecimal format.
* @param params.recipientPublicKeyHex - The recipient's public key in hexadecimal format.
* @param params.paymentAmount - The payment amount for the transaction, specified in motes.
* @param params.chainName - The name of the Casper network chain (e.g., "casper", "casper-test"). Defaults to Mainnet.
* @param params.ttl - The time-to-live (TTL) for the deploy in milliseconds. Defaults to the constant `DEFAULT_DEPLOY_TTL`.
* @param params.tokenId - The ID of the token to transfer. Optional and used if the standard requires it.
* @param params.tokenHash - The hash of the token to transfer. Optional and used if the standard requires it.
*
* @returns A deploy object representing the NFT transfer operation.
*
* @example
* ```ts
* import { makeNftTransferDeploy, NFTTokenStandard } from 'casper-js-sdk';
*
* const deploy = await makeNftTransferDeploy({
* nftStandard: NFTTokenStandard.CEP47,
* contractPackageHash: '0123456789asdfbcdef...',
* senderPublicKeyHex: '0123456789asdfbcdef...',
* recipientPublicKeyHex: '0123456789abcdef...',
* paymentAmount: '3000000000', // 3 CSPR
* tokenId: 234,
* });
*
* console.log('Created Deploy:', deploy);
* ```
*/
export const makeNftTransferDeploy = ({
nftStandard,
contractPackageHash,
senderPublicKeyHex,
recipientPublicKeyHex,
paymentAmount,
chainName = CasperNetworkName.Mainnet,
ttl = DEFAULT_DEPLOY_TTL,
tokenId,
tokenHash
}: IMakeNftTransferDeployParams): Deploy => {
const senderPublicKey = PublicKey.newPublicKey(senderPublicKeyHex);

if (!(tokenId || tokenHash)) {
throw new Error('Specify either tokenId or tokenHash to make a transfer')
}

let args: Args | null = null;

if (nftStandard === NFTTokenStandard.CEP47) {
if (!tokenId) {
throw new Error('TokenId is required for CEP-47 transfer')
}

args = getRuntimeArgsForCep47Transfer({ tokenId, recipientPublicKeyHex })
}

if (nftStandard === NFTTokenStandard.CEP78) {
args = getRuntimeArgsForCep78Transfer({
tokenId,
tokenHash,
senderPublicKeyHex,
recipientPublicKeyHex
});
}

if (!args) {
throw new Error('Deploy arguments error. Check provided token data')
}

const session = new ExecutableDeployItem();

session.storedVersionedContractByHash = new StoredVersionedContractByHash(
ContractHash.newContract(contractPackageHash),
'transfer',
args
);

const payment = ExecutableDeployItem.standardPayment(paymentAmount);

const deployHeader = DeployHeader.default();
deployHeader.account = senderPublicKey;
deployHeader.chainName = chainName;
deployHeader.ttl = new Duration(ttl);

return Deploy.makeDeploy(deployHeader, payment, session);
};

export const getRuntimeArgsForCep78Transfer = ({
tokenHash,
tokenId,
recipientPublicKeyHex,
senderPublicKeyHex
}: Pick<
IMakeNftTransferDeployParams,
'tokenId' | 'recipientPublicKeyHex' | 'tokenHash' | 'senderPublicKeyHex'
>) => {
const runtimeArgs = Args.fromMap({
target_key: CLValue.newCLKey(Key.createByType(PublicKey.fromHex(recipientPublicKeyHex).accountHash().toPrefixedString(), KeyTypeID.Account)),
source_key: CLValue.newCLKey(Key.createByType(PublicKey.fromHex(senderPublicKeyHex).accountHash().toPrefixedString(), KeyTypeID.Account))
});

if (tokenId) {
runtimeArgs.insert(
'is_hash_identifier_mode',
CLValueBool.fromBoolean(false)
);
runtimeArgs.insert('token_id', CLValueUInt64.newCLUint64(tokenId));
}

if (tokenHash) {
runtimeArgs.insert(
'is_hash_identifier_mode',
CLValueBool.fromBoolean(true)
);
runtimeArgs.insert('token_id', CLValueUInt64.newCLUint64(tokenHash));
}

return runtimeArgs;
};

export function getRuntimeArgsForCep47Transfer({
tokenId,
recipientPublicKeyHex
}: Required<
Pick<IMakeNftTransferDeployParams, 'tokenId' | 'recipientPublicKeyHex'>
>) {
return Args.fromMap({
recipient: CLValue.newCLKey(Key.createByType(PublicKey.fromHex(recipientPublicKeyHex).accountHash().toPrefixedString(), KeyTypeID.Account)),
token_ids: CLValueList.newCLList(CLTypeUInt256, [
CLValueUInt256.newCLUInt256(tokenId)
])
});
}
Loading

0 comments on commit 9773801

Please sign in to comment.