# .derupt-ext

{% hint style="info" %}
Work in Progress
{% endhint %}

```
;; title: derupt-ext
;; version: 1.3.1
;; summary: Derupt Extension Contract (sample extension for reference)

;; Derupt Extension Example - Send passed amount of CC to passed principal
(impl-trait 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.derupt-ext-trait.derupt-ext)

(use-trait cryptocash-token-trait 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.cryptocash-token-trait.cryptocash-token)
(use-trait cryptocash-core-trait 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.cryptocash-core-trait.cryptocash-core)

(use-trait sip-009-trait-ft-standard 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.sip-009-trait-nft-standard.sip-009-trait)
(use-trait sip-010-trait-ft-standard 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.sip-010-trait-ft-standard.sip-010-trait)
(use-trait sip-013-trait-ft-standard 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.sip-013-trait-sft-standard.sip-013-trait)

;; Errors
(define-constant ERR-UNAUTHORIZED (err u100))
(define-constant ERR-NOTFOUND (err u101))
(define-constant ERR-WRONG-CC-TOKEN-VERSION (err u102))

(define-data-var ext-owner principal tx-sender)

(define-map ext-meta principal 
  { 
    name: (string-ascii 24),
    description: (string-ascii 256),
    image: (string-ascii 256)
  }
)

(define-read-only (get-ext-metadata) 
  (ok (unwrap! (map-get? ext-meta (var-get ext-owner)) ERR-NOTFOUND))
)

(define-public (update-ext-owner (new-ext-owner principal)) 
  (begin 
    (asserts! (is-eq tx-sender (var-get ext-owner)) ERR-UNAUTHORIZED)
    (asserts! (is-standard new-ext-owner) ERR-UNAUTHORIZED)
    (var-set ext-owner new-ext-owner)
    (print {prev-owner: tx-sender, new-owner: new-ext-owner})
    (ok true)
  )
)

(define-read-only (get-ext-owner) 
  (ok (var-get ext-owner))
)

(define-public (update-ext-metadata (name (optional (string-ascii 24))) (description (optional (string-ascii 256))) (image (optional (string-ascii 256)))) 
  (let 
    (
      (meta (map-get? ext-meta (var-get ext-owner)))
      (prev-name (unwrap! (get name meta) ERR-NOTFOUND))
      (prev-description (unwrap! description ERR-NOTFOUND))
      (prev-image (unwrap! image ERR-NOTFOUND))
    ) 
    (asserts! (is-eq tx-sender (var-get ext-owner)) ERR-UNAUTHORIZED)
    (match name value (map-set ext-meta (var-get ext-owner) {name: value, description: prev-description, image: prev-image}) false)
    (match description value (map-set ext-meta (var-get ext-owner) {name: prev-name, description: value, image: prev-image}) false)
    (match image value (map-set ext-meta (var-get ext-owner) {name: prev-name, description: prev-description, image: value}) false)
    (print { prev-name: prev-name, new-name: (unwrap! name ERR-NOTFOUND), prev-description: prev-description, description: (unwrap! description ERR-NOTFOUND), prev-image: prev-image, image: (unwrap! image ERR-NOTFOUND)})
    (ok true)
  )
)


;; Get derupt-core-contract - used to verify call origin
(define-private (get-derupt-core-contract)
  (contract-call? 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.derupt-feed get-derupt-core-contract) 
)

;; Get cc-token-contract - used to get active cc token contract
(define-private (get-cc-token-contract)
  (contract-call? 'ST1ZK4MRVTQQJMVAAJQWBV2WPQ87QV2851YCTHD7X.derupt-feed get-cc-token-contract) 
)

;; Transfer CryptoCash
(define-public (cryptocash-transfer (cc-token-contract <cryptocash-token-trait>) (amount uint) (recipient principal))
  (contract-call? cc-token-contract transfer amount tx-sender recipient none)
)

;; Execute Extension Function
(define-public (exec-ext-func 
    (extras (optional (list 10 
      {
        stringutf8: (optional (string-utf8 256)), 
        stringascii: (optional (string-ascii 256)), 
        uint: (optional uint), 
        int: (optional int), 
        principal: (optional principal), 
        bool: (optional bool),
        buff: (optional (buff 34)),
        proxy: (optional (buff 2048)),
        cryptocash-token-contract: (optional <cryptocash-token-trait>),
        cryptocash-core-contract: (optional <cryptocash-core-trait>),
        sip-009-contract: (optional <sip-009-trait>),
        sip-010-contract: (optional <sip-010-trait>),
        sip-013-contract: (optional <sip-013-trait>)
      }))
    )
  )
    (let
      ;;get and verify call is coming from current core.
      (
        (derupt-core-contract (unwrap! (get-derupt-core-contract) ERR-NOTFOUND))  
        (cc-token-address (unwrap! (get-cc-token-contract) ERR-WRONG-CC-TOKEN-VERSION)) 
        (cc-token-contract (unwrap! (get cryptocash-token-contract (element-at? (unwrap! extras ERR-NOTFOUND) u0)) ERR-NOTFOUND))  
        ;; Amount extraction from position x of expected tuple arguments
        (amount (unwrap! (unwrap! (get uint (element-at? (unwrap! extras ERR-NOTFOUND) u0)) ERR-NOTFOUND) ERR-NOTFOUND))  
        (recipient (unwrap! (unwrap! (get principal (element-at? (unwrap! extras ERR-NOTFOUND) u0)) ERR-NOTFOUND) ERR-NOTFOUND))  
      )
      (asserts! (is-eq contract-caller derupt-core-contract) ERR-UNAUTHORIZED)    
      (asserts! (is-eq (contract-of cc-token-contract) cc-token-address) ERR-NOTFOUND) 

      ;; perform cc transfer?
      (try! (cryptocash-transfer cc-token-contract amount recipient))

      ;; Print logging
      (print 
        { 
          event: "derupt-ext-message: Transfer CC Too", 
          tx-sender: tx-sender, 
          recipient: recipient,
          extras: extras,
          amount:amount
        }
      )
      (ok true)
    )
)

(map-insert ext-meta (var-get ext-owner) {name: "Transfer CC too", description: "Extension to Transfer an AMOUNT of CC to defined PRINCIPAL", image: "https://stackers.cc/cryptocash.png"})
```

## Extension Contract Metadata

The extension *contract metadata* represents the top level summary of the extension.

```json
{
  "name": "Transfer CC too",
  "description": "https://stackers.cc/derupt-ext-metadata.json",
  "image": "https://stackers.cc/more-cc.gif"
}
```

## Extension Description Metadata

The extension *description metadata* enables greater control over the integration and functionality of the Extension within the Derupt UX/UI, facilitating for you:

* Extension Information Summary (`info`):
  * A general Summary / Explanation of the Extension
* Availability for specific Core Operation (`ops`):
  * To enable use of the Extension by Derupt Core Operations
* Applicable Transaction Post Conditions (`postconditions`):
  * Set the appropriate type: `ft`, `nft`, and or `stx`
* Function Arguments from the User (`argsFromUser`)
  * To enable the applicable argument input fields to be rendered and supplied by the user. \
    (`render` set visibility of the argument input field to the user in the Extension options modal)\
    (`label` set the label you want to apply to the visible field)\
    (`order` set the rendered order of argument input fields)\
    (`optional` representative if input field is an optional input \[`false` means the argument input field is required, `true` means the argument input field is optional]) \
    \
    \&#xNAN;*Note: `argsFromUser` are passed as `extra` function arguments in core operation calls.*

```json
{
    "info": "Extension to Transfer a AMOUNT of CC to a PRINCIPAL (TESTNET)",
    "ops": {
        "send-message": false,
        "like-message": true,
        "dislike-message": true,
        "favorable-reply-message": true,
        "unfavorable-reply-message": true,
        "gift-message": true
    },
    "postconditions": [
        {
            "type": "ft",
            "contractAddress": "ST1ZK0A249B4SWAHVXD70R13P6B5HNKZAA0WNTJTR.cryptocash-token:cryptocash"
        }
    ],
    "argsFromUser": {
        "0": {
            "uint": {
                "render": true,
                "label": "Amount",
                "order": 0,
                "optional": false
            },
            "principal": {
                "render": true,
                "label": "Recipient Principal",
                "order": 1,
                "optional": false
            }
        }
    }
}
```

{% hint style="warning" %}
Extension Contract Metadata pointers is updated via `update-metadata`&#x20;
{% endhint %}

{% hint style="warning" %}
Extension Description Metadata is updated via `derupt-ext-metadata.json` \
(or equivalent)&#x20;
{% endhint %}

{% hint style="warning" %}
Extensions must follow[`.derupt-ext-trait`](https://docs.derupt.io/latest/contracts/.derupt-ext-trait) standard
{% endhint %}

{% hint style="warning" %}
Extension execution `exec-ext-func` function, taking `extras` as an argument. \
\
Developers should define`argsFromUser` to ensure specific fields are presented to the user during the presentation of `ExtensionModal` in order to collect users input if needed.
{% endhint %}

{% hint style="warning" %}
Users can have only 1 extension called, per core function call: eg

* can have 1 `ext` called during `send-message`
* can have 1 `ext` called during `like-message`&#x20;
* can have 1 `ext` called during `dislike-message`
* can have 1 `ext` called during `favorable-reply-message`
* can have 1 `ext` called during `unfavorable-reply-message`
* can have 1 `ext` called during `gift-message`

(note: users can change the enabled extension over time)
{% endhint %}
