Skip to content

Commit

Permalink
added graphics / ipfs tuts / cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
nillo committed Oct 25, 2023
1 parent 3dcd8c0 commit eb83cae
Show file tree
Hide file tree
Showing 16 changed files with 280 additions and 23 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions packages/apps/docs/src/pages/marmalade/architecture/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,16 @@ the user experience by simplifying token creation and management.
## Ledger

The ledger functions as the primary contract responsible for user interaction.

Marmalade is a system of multiple contracts, that calls functions in layers. The
main contract in Marmalade is `marmalade-v2.ledger`, which stores the token
information, token's accounts, and the policies associated with it. The main
functions are `create-token`, `mint`, `burn`, `transfer`, `sale`.

For more info on the ledger please click [here](/marmalade/architecture/ledger)

![Leder meets Policy Manager](/assets/marmalade/mint_flow.png)

## Policy Manager

Marmalade V1 tokens were designed to be governed by a single policy that allows
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,4 @@ Marmalade makes it possible.

---

[Ledger Code](https://github.com/kadena-io/marmalade/blob/v2/pact/ledger.pact)
[Ledger Contract](https://github.com/kadena-io/marmalade/blob/v2/pact/ledger.pact)
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,4 @@ Marmalade ecosystem. Happy crafting!

---

[Policy Manager Code](https://github.com/kadena-io/marmalade/blob/v2/pact/policy-manager/policy-manager.pact)
[Policy Manager Contract](https://github.com/kadena-io/marmalade/blob/v2/pact/policy-manager/policy-manager.pact)
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,71 @@ layout: full

# Sale Contracts

With Sale Contracts, Marmalade V2 introduces a new way to manage the sale of a token. WHen offering a token up for sale in the ledger, it is now possible to also provide a reference to a sale contract. This sale contract can then be used to manage the sale of the token which allows for maximum flexibility and creativity in the sale of a token.

Security is an important aspect of selling a token, especially when it comes to guaranteeing royalty. Therefore the sale contracts are required to be registered within the Policy Manager. This ensures that the sale contract is known to the Policy Manager and that the Policy Manager can enforce the sale contract. Before registering the sale contract will undergo a review process to ensure that it is safe to use.

Where Sale Contracts are aimed at general purpose sales, Marmalade token creators still have complete flexibility to implement any custom sale logic within a policy and attach it to the token itself. This allows for a wide range of sale options and flexibility.
With Sale Contracts, Marmalade V2 introduces a new way to manage the sale of a
token. WHen offering a token up for sale in the ledger, it is now possible to
also provide a reference to a sale contract. This sale contract can then be used
to manage the sale of the token which allows for maximum flexibility and
creativity in the sale of a token.

Security is an important aspect of selling a token, especially when it comes to
guaranteeing royalty. Therefore the sale contracts are required to be registered
within the Policy Manager. This ensures that the sale contract is known to the
Policy Manager and that the Policy Manager can enforce the sale contract. Before
registering the sale contract will undergo a review process to ensure that it is
safe to use.

Where Sale Contracts are aimed at general purpose sales, Marmalade token
creators still have complete flexibility to implement any custom sale logic
within a policy and attach it to the token itself. This allows for a wide range
of sale options and flexibility.

## Sale Contract Interface

The sale contract interface is a light interface which needs to be implemented by any sale contract. It is used by the Policy Manager to enforce the sale contract. The interface is defined as follows:
The sale contract interface is a light interface which needs to be implemented
by any sale contract. It is used by the Policy Manager to enforce the sale
contract. The interface is defined as follows:

```pact
(defun enforce-quote-update:bool (sale-id:string price:decimal)
@doc "Read-only Function that is enforced to update quote price at enforce-buy"
)
```

The function `enforce-quote-update` is called in from the `buy` step in the ledger and takes two parameters:
The function `enforce-quote-update` is called in from the `buy` step in the
ledger and takes two parameters:

- sale-id (type: string): This parameter represents the identifier of the sale, which is basicaly the pact-id that is created when the token is offered up for sale in the ledger.
- price (type: decimal): This parameter represents the finale price associated with the sale.
- sale-id (type: string): This parameter represents the identifier of the sale,
which is basicaly the pact-id that is created when the token is offered up for
sale in the ledger.
- price (type: decimal): This parameter represents the finale price associated
with the sale.

## Available Sale Contracts
The available sale contracts are listed below. More sale contracts will follow but in the meantime, you can also create your own sale contract. The sale contracts can be found in the [Marmalade Github repository](https://github.com/kadena-io/marmalade/tree/v2/pact/sale-contracts) under `pact/sale-contracts`. Just create a pull request and we will review your sale contract and take care of deployment and whitelisting it in the Policy Manager.

**Conventional Auction** (Mainnet deployment pending)
The available sale contracts are listed below. More sale contracts will follow
but in the meantime, you can also create your own sale contract. The sale
contracts can be found in the
[Marmalade Github repository](https://github.com/kadena-io/marmalade/tree/v2/pact/sale-contracts)
under `pact/sale-contracts`. Just create a pull request and we will review your
sale contract and take care of deployment and whitelisting it in the Policy
Manager.

A conventional auction is a sale contract that allows for the sale of a token through a conventional auction. The seller can set a reserve price which will ensure that the token is not sold below a certain price. The auction will run for a set amount of time and the highest bidder will win the auction. If the reserve price is not met, the seller can choose to cancel the auction and the token will be returned to the seller.
The contract is deployed at `marmalade-sale.conventional-auction`.
**Conventional Auction** (Mainnet deployment pending)

A conventional auction is a sale contract that allows for the sale of a token
through a conventional auction. The seller can set a reserve price which will
ensure that the token is not sold below a certain price. The auction will run
for a set amount of time and the highest bidder will win the auction. If the
reserve price is not met, the seller can choose to cancel the auction and the
token will be returned to the seller. The contract is deployed at
`marmalade-sale.conventional-auction`.

## Using a Sale Contract
The sale contract can be used by providing the sale contract's module name as part of the quote specification when calling the `offer` function in the ledger. Here's an example of the quote specification with the sale contract's module name mentioned under the key `sale-type`.

The sale contract can be used by providing the sale contract's module name as
part of the quote specification when calling the `offer` function in the ledger.
Here's an example of the quote specification with the sale contract's module
name mentioned under the key `sale-type`.

```pact
"quote" : {
Expand All @@ -54,6 +87,8 @@ The sale contract can be used by providing the sale contract's module name as pa
}
```

**_Note:_** When using a sale contract the `sale-price` during `offer` must always be `0.0`, since the sale contract will be responsible for updating the price during the `buy` step.
**_Note:_** When using a sale contract the `sale-price` during `offer` must
always be `0.0`, since the sale contract will be responsible for updating the
price during the `buy` step.

[Sale Interface Code](https://github.com/kadena-io/marmalade/blob/v2/pact/policy-manager/sale.interface.pact)
[Sale Interface Contract](https://github.com/kadena-io/marmalade/blob/v2/pact/policy-manager/sale.interface.pact)
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,6 @@ share your favorite tokens in a safe and organised way.

---

[Quick guide: Creating a collection]: (/)
[Quick guide: Creating a collection]: Coming soon

[Collection Policy Code](https://github.com/kadena-io/marmalade/blob/v2/pact/concrete-policies/collection-policy/collection-policy-v1.pact)
[Collection Policy Contract](https://github.com/kadena-io/marmalade/blob/v2/pact/concrete-policies/collection-policy/collection-policy-v1.pact)
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,4 @@ In summary, the Guard policy ensures the safety and integrity of digital assets.

---

[Guard Policy Code](https://github.com/kadena-io/marmalade/blob/v2/pact/concrete-policies/guard-policy/guard-policy-v1.pact)
[Guard Policy Contract](https://github.com/kadena-io/marmalade/blob/v2/pact/concrete-policies/guard-policy/guard-policy-v1.pact)
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ creation.

---

[Non Fungible Policy Code](https://github.com/kadena-io/marmalade/blob/v2/pact/concrete-policies/non-fungible-policy/non-fungible-policy-v1.pact)
[Non Fungible Policy Contract](https://github.com/kadena-io/marmalade/blob/v2/pact/concrete-policies/non-fungible-policy/non-fungible-policy-v1.pact)
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,4 @@ ongoing value of their creations.

---

[Royalty Policy Code](https://github.com/kadena-io/marmalade/blob/v2/pact/concrete-policies/non-fungible-policy/non-fungible-policy-v1.pact)
[Royalty Policy Contract](https://github.com/kadena-io/marmalade/blob/v2/pact/concrete-policies/non-fungible-policy/non-fungible-policy-v1.pact)
165 changes: 165 additions & 0 deletions packages/apps/docs/src/pages/marmalade/metadata/ipfs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
---
title: IPFS Storage
description: Leveraging IPFS in Marmalade
menu: IPFS Storage
label: IPFS Storage
order: 2
layout: full
---

# Leveraging IPFS in Marmalade

Given the immutable characteristic of NFTs, the associated data's long-term
accessibility and sustainability are critical aspects to consider. IPFS has
emerged as a powerful tool to handle these requirements, and its importance is
underscored in the context of Marmalade,

IPFS is a pioneering protocol designed to modernise the internet's foundational
structures, augmenting its capacity for storing, addressing, and accessing data.
This technology is central to our approach in dealing with NFT data, ensuring
its perpetual availability and integrity and thereby strengthening the overall
dependability of the NFTs hosted on Marmalade.

Our guide offers you an easy-to-follow examples for storing your NFT data on
IPFS, aiming to make this process as effortless as possible. These best
practices, which cater to both extensive asset collections and individual NFTs,
are crafted to ensure your data's resilience and longevity in the IPFS
ecosystem.

## Guide

This guide provides our recommend approach to storing metadata and image assets
on IPFS, leveraging hypothetical paths and CIDs. Our manual illustrates two
distinctive storage scenarios and outlines the method for accessing stored data.

### Storing Collections: Step-by-Step Guide

1. **Image Upload to IPFS:**

- Uploading your image assets folder to IPFS, adopting sequential numbering
for streamlined referencing (e.g., `1.jpg, 2.jpg...`).

2. **Metadata Update:**

- After the upload, capture the CID for the assets folder (e.g.,
"Bayfol...").
- Proceed to update the metadata files, correlating the image property with
the path to CID (e.g., `ipfs://Bayfol.../1.jpg`).

3. **Metadata Upload to IPFS:**

- Upload the metadata files to IPFS, maintaining sequential numbering that
corresponds with the asset (e.g., `1.json, 2.json...`).
- Retrieve the CID for the uploaded metadata folder (e.g., "Baymetx...).

4. **Finalizing URI:**

- Merge the metadata folder CID (e.g., "Baymetx...") with the respective
filename and extension to construct a comprehensive URI (e.g.,
`ipfs://Baymetx.../1.json`).

### Example:

- **uri:**
`ipfs://bafybeig4ihtm2phax2eodfpubwy467szuiieqafkoywp5khzt6cz2hqrna/1.json`
- **gateway:**
[[click here]](https://bafybeig4ihtm2phax2eodfpubwy467szuiieqafkoywp5khzt6cz2hqrna.ipfs.dweb.link/1.json)

- **collection-asset-folder:**
`ipfs://bafybeie4ktsgx4x3gnpvo2uptngez4cvvqdq75iimpnukvpee2x34yp6jm`

- **collection-asset-folder-gateway:**
[[click here]](https://bafybeie4ktsgx4x3gnpvo2uptngez4cvvqdq75iimpnukvpee2x34yp6jm.ipfs.dweb.link/)
- **collection-metadata-folder:**
`ipfs://bafybeig4ihtm2phax2eodfpubwy467szuiieqafkoywp5khzt6cz2hqrna`

- **collection-metadata-folder-gateway:**
[[click here]](https://bafybeig4ihtm2phax2eodfpubwy467szuiieqafkoywp5khzt6cz2hqrna.ipfs.dweb.link/)

### Single NFT Storage: Step-by-Step Guide

1. **Image and Metadata Upload to IPFS:**

- Upload the image asset to IPFS.

2. **Metadata Update:**

- Upon successful upload, retrieve the CID for the asset (e.g.,
"Bayfabc...").
- Revise the metadata files, matching the image property with the path to
CID (e.g., `ipfs://Bayfabc.../1.jpg`).

3. **Metadata Upload to IPFS:**

- Upload the metadata file to IPFS.

4. **Finalizing URI:**

- Retrieve the path containing the CID for the uploaded metadata file (e.g.,
`ipfs://Bayfxyz.../metadata.json" `)

### Example:

- **uri:**
`ipfs://bafyreiainnf575ivbxffep3xqx4d4v2jrpyz4yrggylfp5i7lru7zpfese/metadata.json`
- **gateway-link:**
[[click here]](https://bafyreiainnf575ivbxffep3xqx4d4v2jrpyz4yrggylfp5i7lru7zpfese.ipfs.dweb.link/metadata.json)

### Metadata Structure

Your metadata files should adhere to our [JSON schema](/marmalade/metadata). The
schema provides a structure for your metadata, ensuring that necessary details
are present and formatted correctly. This schema can be found within this
readme.

In this schema, the `image` property should contain a link to the image on IPFS
(as illustrated in the previous examples).

### Token Creation in the Ledger

When creating a token in the ledger, you should use the `create-token` function.
The link obtained from IPFS (.json) serves as the URI supplied to create a token
within the ledger:

```pact
(defun create-token:bool
( id:string
precision:integer
uri:string
policies:[module{kip.token-policy-v2}]
)
...
)
```

Please be reminded that these CIDs are hypothetical and should be tailored to
match your specific use case and IPFS setup. A thorough understanding of the
IPFS storage mechanism is crucial, and the steps should be adjusted as
necessary.

By faithfully following these detailed steps, you can efficiently store metadata
and image assets on IPFS, associate them with NFTs, and seamlessly retrieve them
in your DApp or application.

### URI retrieval from Ledger

Retrieving the URI for a specific token from the ledger is facilitated through a
function called `get-uri`. This function requires a token ID as its argument and
returns the associated URI.

```pact
(defun get-uri:string (id:string)
(at 'uri (read tokens id))
)
```

When you call the `get-uri` function and pass in a token ID, it will access the
`tokens` map, find the row corresponding to the provided token ID, and return
the value stored in the `'uri` field of that row. Essentially, it retrieves the
URI that corresponds to the token ID you specified.

Thus, by utilising this `get-uri` function, you can efficiently retrieve the URI
associated with any token stored within the ledger by simply providing its token
ID.
1 change: 1 addition & 0 deletions packages/tools/kadena-cli/.kadena/keys/andy.plain.key
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"publicKey":"451abcee2d59decc36f67aaf4ab852602c61e9e1bc3e1c495c2ac8fc63a0a581","privateKey":"1fbc57ef245cab304ef21b168cd0c3b3fd50e6add794808c4582954feeb9c5f5"}
1 change: 1 addition & 0 deletions packages/tools/kadena-cli/.kadena/keys/b.hd.phrase
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
marine shoe thunder census minor mirror bargain evoke limb biology episode silk
1 change: 1 addition & 0 deletions packages/tools/kadena-cli/.kadena/keys/n.hd.phrase
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
left rare pave unhappy raccoon club shield glad license matter catalog bonus
4 changes: 4 additions & 0 deletions packages/tools/kadena-cli/.kadena/networks/mainnet.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
network: mainnet
networkId: mainnet01
networkHost: https://api.chainweb.com
networkExplorerUrl: https://explorer.chainweb.com/mainnet/tx/
4 changes: 4 additions & 0 deletions packages/tools/kadena-cli/.kadena/networks/testnet.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
network: testnet
networkId: testnet01
networkHost: https://api.testnet.chainweb.com
networkExplorerUrl: https://explorer.chainweb.com/testnet/tx/
38 changes: 38 additions & 0 deletions packages/tools/kadena-cli/src/keys/legacy/chainweaver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { binToHex, hexToBin } from '@kadena/cryptography-utils';

import lib from 'cardano-crypto.js/kadena-crypto.js';

export function generateSeedPhrase(): string {
const seedPhrase = lib.kadenaGenMnemonic();
return seedPhrase;
}

export const getKeyPairsFromSeedPhrase = (
seedPhrase: string,
index: number = 0,
): { publicKey: string; secretKey: string } => {
const root = lib.kadenaMnemonicToRootKeypair('', seedPhrase);
const hardIndex = 0x80000000;
const newIndex = hardIndex + index;
const [privateRaw, pubRaw] = lib.kadenaGenKeypair('', root, newIndex);
const axprv = new Uint8Array(privateRaw);
const axpub = new Uint8Array(pubRaw);
const pub = binToHex(axpub);
const prv = binToHex(axprv);
return {
publicKey: pub,
secretKey: prv,
};
};

export function isValidSeedPhrase(seedPhrase: string): boolean {
return lib.kadenaMnemonicCheck(seedPhrase);
}

export function getSignatureFromHash(hash: string, privateKey: string): string {
const newHash = Buffer.from(hash, 'base64');
const u8PrivateKey = hexToBin(privateKey);
const signature = lib.kadenaSign('', newHash, u8PrivateKey);
const s = new Uint8Array(signature);
return binToHex(s);
}

0 comments on commit eb83cae

Please sign in to comment.