AptoORM is a utility for Object–relational mapping from Typescript and Javascript class objects to Aptos Object model.
Once you define a class in your source code with AptoORM decorators, you can record the class objects to Aptos Blockchain. It is also supported to update, delete them on chain and to transfer the ownership of the objects to others as like other digital assets.
Furthermore, AptoORM
can be a framework to create, mint NFT on Aptos Blockchain with simple and clear settings.
- Add
OrmObject
toOrmClass
decorator. - Add
OrmToken
toOrmTokenClass
decorator. - Add ORM Token generation to
gen-move.ts
. - Remove
OrmToken
's name, description and uri from user data. - Add OrmToken's name, description and uri fields update procedure with
token_mutable_by_creator
andtoken_mutable_by_owner
options. - Rename
OrmCollection
toOrmTokenClass
. - Add update and delete operations for
OrmToken
. - Add an option,
immutable
, for thename
,uri
anddescription
fields ofOrmToken
. - Updated
get
function generated by user-defined class. - Add Aptos Collection object name option to
OrmTokenConfig
. - Add
constant
option toOrmTokenConfig
for fixedname
,uri
anddescription
fields ofOrmToken
. The OrmToken has the same name, uri and descriptions if it is configured. - Add
index_fields
option toOrmClass
andOrmField
in order to Aptos create named object. - Add
package
configuration - Add default
royalty_payee
to class object. - Add
OrmFreePrepayClient
,OrmFreePostpayClient
for free transaction fee interface. - Add
PoA
typescript API - Add
create_to
(create and send an object) API - Add
royalty_present_per_token
to represent the royalty to each token. - Add
UpdateDateField()
,CreateDateField()
. - Add new
OrmField
option (token_property
) to add/delete the field from/to token's property_map. - Add txn result parser to get the object or token created.
- Add Indexer function to list the created objects.
- Check need to add the move ability [key, store, drop, copy] should be controlled by the AptoORM.
- Add CLIs for example.
Install the npm package:
npm install apto_orm --save
You need to install reflect-metadata:
npm install reflect-metadata --save
and import it somewhere in the global place of your app (for example in app.ts):
import "reflect-metadata"
You may need to install node typings:
npm install @types/node ts-node --save-dev
ts-node
is required to execute theapto_orm cli
.
Also, make sure you are using TypeScript version 4.5 or higher, and you have enabled the following settings in tsconfig.json:
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
You can start a project with apto_orm
from scratch. Try the following.
# package.json
pnpm init
# add build command to package.json
jq --arg key "build" --arg val "tsc --build" '.scripts[$key]=$val' package.json\
| jq "." > _package.json && mv _package.json package.json
# add `apto_orm` command to package.json
jq --arg key "orm" --arg val "apto_orm" '.scripts[$key]=$val' package.json \
| jq "." > _package.json && mv _package.json package.json
# setup tsconfig
{
echo "{"
echo ' "compilerOptions": {'
echo ' "target": "ES2020",'
echo ' "module": "CommonJS",'
echo ' "moduleResolution": "node",'
echo ' "skipLibCheck": true,'
echo ' "resolveJsonModule": true,'
echo ' "esModuleInterop": true,'
echo ' "emitDecoratorMetadata": true,'
echo ' "experimentalDecorators": true,'
echo ' "allowSyntheticDefaultImports": true,'
echo ' "declaration": false,'
echo ' "outDir": "dist"'
echo ' },'
echo ' "include": ["src"],'
echo ' "exclude": ["node_modules", "**/*.spec.ts"]'
echo "}"
} > tsconfig.json
# setup .gitignore.
{
echo 'dist'
echo 'out'
echo 'build'
echo 'node_modules'
echo '**/build'
echo '.key'
} > .gitignore
# Create a keypair to .key directory
mkdir -p .key
aptos key generate --assume-yes --output-file .key/villain
# Initialize Aptos account and receive funds of Aptos Coin
# if devnet or testnet because your package publishing costs Aptos Coin.
aptos init --network devnet --private-key-file .key/villain --profile villain
Create your sample typescript class by apto_orm
init
command.
This command will create a class file (MyToken.ts
) to src/my_tokens
.
npx apto_orm init src/my_tokens --key .key/villain --token -c MyToken
Modify the following token class to suit your taste.
import { OrmTokenClass, OrmField, OrmIndexField } from 'apto_orm';
@OrmTokenClass({
package_address: '0x43ded2bab6265e70d3fe47879e2af7d7826984c1f44e5fe6cb4912678c3cab40',
package_creator: '0x8953be30cc7c69682a2aa972fefee8d8ba474eb69830349d03cda73f5568e8ff',
package_name: 'my_tokens',
collection_name: 'AptoORM MyToken',
collection_uri: 'https://raw.githubusercontent.com/neoul/apto_orm/main/resource.png',
collection_description: 'Sample AptoORM Token',
max_supply: 1000n,
token_use_property_map: false,
royalty_present: false,
royalty_denominator: 100,
royalty_numerator: 1,
})
export class MyToken {
@OrmIndexField({ immutable: true })
id!: number;
@OrmField({ immutable: true })
name!: string;
@OrmField()
uri!: string;
@OrmField()
description!: string;
}
The following command generates a Move module based on your class to
YOUR_PACKAGE_PATH/move
.
npx apto_orm generate src/my_tokens
# classes 'MyToken' are created to the package 'my_tokens'
# - creator: 0x8953be30cc7c69682a2aa972fefee8d8ba474eb69830349d03cda73f5568e8ff
# - address: 0x43ded2bab6265e70d3fe47879e2af7d7826984c1f44e5fe6cb4912678c3cab40
# - path: /home/willing/projects/apto_example/src/my_tokens
The generated module must be compiled and published to your package account.
This package account is an object that has the signer capability of your package
and is a place where your package bytecodes are stored.
npx apto_orm compile src/my_tokens
npx apto_orm publish src/my_tokens --key .key/villain
Please check for information about Aptos Move language.
npx apto_orm create src/my_tokens --key .key/villain -c MyToken \
-d '{ "uri": "https://raw.githubusercontent.com/neoul/apto_orm/main/resource.png", "description": "ok", "id": 1, "name": "ABC" }'
npx apto_orm create src/my_tokens --key .key/villain \
--to 0xfd2984f201abdbf30ccd0ec5c2f2357789222c0bbd3c68999acfebe188fdc09d -c MyToken \
-d '{ "uri": "https://raw.githubusercontent.com/neoul/apto_orm/main/resource.png", "description": "ok", "id": 2, "name": "EFG" }'
npx apto_orm delete src/my_tokens --key .key/villain -c MyToken \
-a 0x10dd8012f4c83a2e058347d7178d81432fcadf30cc11e623e2c8ba93a0a786df
OrmClass
decorates a Typescript class to declare Aptos Object that the Object model allows Move to represent a complex type as a set of resources stored within a single address.
@OrmClass({
package_creator: '0xabc',
package_name: 'Move package name',
deletable_by_owner: true,
...
})
export type OrmObjectConfig = {
/** The creator address of the object and package */
package_creator: AptosAccount | MaybeHexString;
/** The package name where the objects belongs to */
package_name: string;
package_address?: MaybeHexString; // address of the package
/** Aptos creates named objects with predictable hash addresses, which are derived
* from user input and the creator's address. This enables named objects to be indexed
* and traced based on the user input provided by the creator.
* AptoORM facilitates the creation of indexable objects by utilizing `index_fields`
* to organize the fields used in the named object creation.
* Conversely, if index_fields is not set, OrmObject is created with a random address. */
index_fields?: string[];
/** Objects created by the class can be transferred by `object::transfer()`. */
direct_transfer?: boolean;
/** The creator (The owner of OrmCreator object) can remove the ORM objects. */
deletable_by_creator?: boolean;
/** The owner can remove the ORM objects */
deletable_by_owner?: boolean;
/** The creator can transfer the ORM objects by AptoORM facilities. */
indirect_transfer_by_creator?: boolean;
/** The owner can transfer the ORM objects by AptoORM facilities. */
indirect_transfer_by_owner?: boolean;
/** The creator can extend the ORM objects. */
extensible_by_creator?: boolean;
/** The owner can extend the ORM objects. */
extensible_by_owner?: boolean;
named_addresses?: NamedAddresses;
/** The token configuration must be set if the OrmObject is Aptos Token object. */
token_config?: OrmTokenConfig;
};
OrmTokenClass
is used to define custom Aptos Token Object. The OrmTokenClass
should be defined with the OrmObjectConfig
and additional following attributes.
/** ORM Token configuration */
export type OrmTokenConfig = {
/** The representative name of the token collection (= Aptos Collection Name) */
collection_name: string;
/** The representative URI of the token collection (= Aptos Collection URI) */
collection_uri: string;
/** The representative description of the token collection (= Aptos Collection Description) */
collection_description: string;
/** The maximum token supply of the AptoORM class (= Aptos Collection Max Supply) */
max_supply: number | bigint;
/** Whether the token uses property map */
token_use_property_map: boolean;
/** Whether the token has royalty or the collection has royalty itself. */
royalty_present: boolean;
/** The payee of the royalty */
royalty_payee: MaybeHexString | string;
/** The denominator of the royalty */
royalty_denominator: number;
/** The numerator of the royalty */
royalty_numerator: number;
};
OrmField
and OrmIndexField
must be used in the fields of the class decorated by OrmClass
and OrmTokenClass
. Each class fields decorated by the OrmField
becomes the field of the resource in an Aptos Object.
POA Account is an account that can generate and transfer the transaction. The account has the POA (Power of attorney) creates AptoORM Objects instead of the NFT Creator.
aptos key generate --assume-yes --output-file .key/poa1
aptos init --network devnet --private-key-file .key/poa1 --profile poa1
npx apto_orm poa register -d .key/villain -l .key/poa1
npx apto_orm poa show -l .key/poa1
npx apto_orm create src/my_tokens --key .key/poa1 -c MyToken \
-d '{ "uri": "https://raw.githubusercontent.com/neoul/apto_orm/main/resource.png", "description": "ok", "id": 100, "name": "ABC" }'
# [How to build, test and run]
# testing
docker build --target apto_orm-testing -t apto_orm-testing .
# Building
docker build -t apto_orm .
# Running
docker run -d -p 8080-8082:8080-8082 -p 9101:9101 -p 50051:50051 -p 5678:5678 --name apto_orm apto_orm
# Downloading keys and .env
curl http://localhost:8082/download.sh | sh
Or you can setup AptoORM at once.
./run.sh setup
orm_creator
module provides a signer object that becomes the creator of AptoORM class objects in order to support the programmatic onchain resource handling. The signer object that has OrmCreator
resource returns back its signer if the transaction sender (signer) is the owner of the signer object. It also returns the signer if other accounts authorized by the owner through PowerOfAttorney
resource declaration. The owner account can register or revoke the authorized accounts directly or via the proof challenge.
orm_class
module is used to store the onchain properties of the user-defined class.
orm_module
is used to designate the orm_creator
and orm_class
of your class module.
The orm_module
is recorded to your account that is a placeholder to deploy your class module.
orm_object
... TBD
---
ORM Onchain Resource
---
classDiagram
OrmModule "1" --> "1" OrmCreator: refer
OrmModule "1" --> "1" `OrmClass, OrmTokenClass`: refer
UserData .. `OrmObject, OrmToken`: co-locate in an object
`OrmObject, OrmToken` --> "1" `OrmClass, OrmTokenClass`: refer
`OrmClass, OrmTokenClass` "1" --> "1" OrmCreator: refer
class UserData {
+data: any
}
class OrmCreator {
+publisher: address
+extend_ref: ExtendRef
+load_signer()
+load_signer_by_signer_capability()
}
class `OrmClass, OrmTokenClass` {
+creator: OrmCreator
+config: OrmObjectConfig
}
class OrmModule {
+signer: OrmCreator
+class: OrmClass
}
class `OrmObject, OrmToken` {
+class: OrmClass
}
---
title Onchain accounts in ORM Onchain Architecture
---
flowchart
subgraph OwnerAccount
OwnerAccount::Account
end
subgraph AuthorizedAccount
AuthorizedAccount::Account
AuthorizedAccount::PowerOfAttorney
end
subgraph OrmCreator
OrmCreator::ObjectCore
OrmCreator::OrmCreator
end
subgraph OrmClass
OrmClass::ObjectCore
OrmClass::OrmClass
OrmClass::OrmTokenClass
end
subgraph OrmObject
OrmObject::ObjectCore
OrmObject::OrmObject
OrmObject::OrmToken
OrmObject::UserData
end
OwnerAccount -- give authority (POA) --> AuthorizedAccount
OwnerAccount -- create and load OrmCreator --> OrmCreator
AuthorizedAccount -- load OrmCreator to handle OrmObject --> OrmCreator
OrmCreator -- create/delete/update --> OrmObject
OrmCreator -- own --> OrmClass
OrmObject -- refer --> OrmClass
[설명 추가]