Commit 73b3f4c4 by haojie

1

parent 137b3923
...@@ -58,11 +58,11 @@ protected function form() ...@@ -58,11 +58,11 @@ protected function form()
$form->textarea('remark'); $form->textarea('remark');
$form->submitted(function (Form $form) { $form->submitted(function (Form $form) {
// 选择key自动加上name // $key = $form->key;
// $email = $form->keyList; // // 表里只能存在唯一的key
// $user = \App\Models\User::where('email', $email)->first(); // $config = AdminConfig::query()->where('key', $key)->first();
// if (filled($user) && $user->id != $form->getKey()) { // if (filled($config)) {
// return $form->response()->error('当前邮箱已经存在了'); // return $form->response()->error('当前配置已经存在了');
// } // }
}); });
$form->display('created_at'); $form->display('created_at');
......
<?php
namespace App\Exceptions;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use RuntimeException;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
abstract class AppRuntimeException extends RuntimeException implements HttpExceptionInterface, ExceptionCodePrefixInterface
{
protected $codePrefix;
protected $errors;
protected $status_code;
protected $headers;
protected $data;
public static $errorList = [];
public function getCodePrefix(): int
{
return 1;
}
/**
* @param int $code
* @param string $message
* @param array $errors
* @param int $status_code
* @param array $headers
* @param array $data
*/
public function __construct(int $code = 1, $message = 'error', $errors = [], int $status_code = 400, array $headers = [], array $data = [])
{
parent::__construct();
$code = sprintf("%03d", $code);
$code = (string)($this->getCodePrefix() . $code);
$this->status_code = $status_code;
$this->code = (int)($code);
$this->message = $this->getDefaultMessage($code, $message);
$this->errors = $errors;
$this->headers = $headers;
$this->data = $data;
}
public function getDefaultMessage($code, $message = '')
{
if (filled($message)) {
return $message;
}
return self::$errorList[$code] ?? ($this->message ?? '');
}
public function getStatusCode(): int
{
return $this->status_code;
}
public function getErrors()
{
return count($this->errors) > 0 ? $this->errors : null;
}
public function getData()
{
return $this->data;
}
public function errors()
{
return count($this->errors) > 0 ? $this->errors : null;
}
public function getHeaders(): array
{
return $this->headers;
}
/**
* @param int $status_code
*/
public function setStatusCode(int $status_code): void
{
$this->status_code = $status_code;
}
public static function render(Request $request, self $exception)
{
return $request->expectsJson() ? self::invalidJson($exception) : self::invalid($request, $exception);
}
/**
* 无效json
*
* @param AppRuntimeException $exception
* @param string $lang
* @return \Illuminate\Http\JsonResponse
*/
public static function invalidJson(self $exception)
{
$data = [
'errors' => $exception->errors,
'message' => $exception->getMessage(),
'code' => $exception->getCode(),
'status_code' => $exception->getStatusCode(),
'data' => $exception->getData(),
];
if (app()->environment(['local'])) {
$data['trace'] = $exception->getTrace();
$data['time'] = microtime(true) - LARAVEL_START;
}
return response()->json($data, $exception->getStatusCode(),
$exception->getHeaders());
}
}
<?php
namespace App\Exceptions;
interface ExceptionCodePrefixInterface
{
public function getCodePrefix() : int;
}
<?php
namespace App\Exceptions;
use App\Service\Common\CommonService;
class UserException extends AppRuntimeException
{
public function getCodePrefix(): int
{
return CommonService::USER_CODE;
}
}
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Service\TradeService;
use Illuminate\Http\Request;
use App\Service\InscriptionService;
class TradeController extends Controller
{
// 卖家上架铭文
public function shelves(Request $request)
{
// 付款地址
$payment_address = $request->input('payment_address');
// 交易hash
$hash = $request->input('hash');
# 卖出价格
$price = $request->input('price');
// 铭文信息
$inscription = $request->input('inscription');
$result = app(TradeService::class)->userShelves($payment_address, $hash, $inscription, $price);
return $this->success($result);
}
}
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
namespace App\Http\Controllers\Web; namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Service\AdminConfigService;
use Inertia\Inertia; use Inertia\Inertia;
...@@ -23,9 +24,18 @@ public function shelves() ...@@ -23,9 +24,18 @@ public function shelves()
{ {
// 铭文上架 // 铭文上架
$title = '铭文上架'; $title = '铭文上架';
// 卖出手续费比例
$sell_fee = app(AdminConfigService::class)->getSellFee();
// 最低卖出价格
$sell_min_price = app(AdminConfigService::class)->getSellMinPrice();
// 收款账号
$receipt_account = app(AdminConfigService::class)->getReceiptAccount();
return Inertia::render('InscriptionShelves/index', [ return Inertia::render('InscriptionShelves/index', [
'info' => [ 'info' => [
'title' => $title, 'title' => $title,
"sell_fee" => $sell_fee,
'sell_min_price' => $sell_min_price,
'receipt_account' => $receipt_account
], ],
]); ]);
} }
......
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class InscriptionTrading extends Model
{
use HasFactory;
protected $table = 'inscription_trading';
protected $fillable = [
'content_uri',
'quantity',
'owner',
'creator',
'inscription_created_date',
'inscription_hash',
'original_amount',
'admin_account',
'sell_fee',
'sell_fee_amount',
'buy_fee',
'buy_fee_amount',
'status',
'seller_status',
'buyer_status',
'seller_transfer_inscription_hash',
'seller_receive_hash',
'seller_cancel_hash',
'buyer_pay_hash',
'buyer_receive_inscription_hash'
];
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class TransactionLog extends Model
{
use HasFactory;
protected $table = 'transaction_log';
}
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
namespace App\Service; namespace App\Service;
use App\Models\AdminConfig;
class AdminConfigService class AdminConfigService
{ {
// 配置可选项 // 配置可选项
...@@ -13,6 +15,7 @@ class AdminConfigService ...@@ -13,6 +15,7 @@ class AdminConfigService
public const INSCRIPTION_BUY_FEE = 'inscription_buy_fee'; // 铭文买入手续费比例 public const INSCRIPTION_BUY_FEE = 'inscription_buy_fee'; // 铭文买入手续费比例
public const INSCRIPTION_SELL_MIN_PRICE = 'inscription_sell_min_price'; // 铭文卖出最低价格
// 类型列表 // 类型列表
public const keyList = [ public const keyList = [
...@@ -20,5 +23,71 @@ class AdminConfigService ...@@ -20,5 +23,71 @@ class AdminConfigService
self::RECEIPT_ACCOUNT_TOKEN => '私钥地址', self::RECEIPT_ACCOUNT_TOKEN => '私钥地址',
self::INSCRIPTION_SELL_FEE => '铭文卖出手续费比例', self::INSCRIPTION_SELL_FEE => '铭文卖出手续费比例',
self::INSCRIPTION_BUY_FEE => '铭文买入手续费比例', self::INSCRIPTION_BUY_FEE => '铭文买入手续费比例',
self::INSCRIPTION_SELL_MIN_PRICE => "铭文卖出最低价格"
];
// 要换算成百分比的类型
public const percentList = [
self::INSCRIPTION_SELL_FEE,
self::INSCRIPTION_BUY_FEE,
]; ];
public function model()
{
return new AdminConfig();
}
// 获取单个配置
public function getConfig(string $key)
{
$model = $this->model()->where('key', $key)->where('status', 1)->first();
if (filled($model)) {
return $model->value;
}
return '';
}
// 获取卖家手续费比例
public function getSellFee()
{
$sell_fee = $this->getConfig(self::INSCRIPTION_SELL_FEE);
if (!$sell_fee) {
// 设置默认值
$sell_fee = 0.01;
}
return $sell_fee;
}
// 获取买家手续费比例
public function getBuyFee()
{
$buy_fee = $this->getConfig(self::INSCRIPTION_BUY_FEE);
if (!$buy_fee) {
// 设置默认值
$buy_fee = 0.01;
}
return $buy_fee;
}
// 获取最低卖出价格
public function getSellMinPrice()
{
$sell_min_price = $this->getConfig(self::INSCRIPTION_SELL_MIN_PRICE);
if (!$sell_min_price) {
// 设置默认值
$sell_min_price = '5';
}
return $sell_min_price;
}
// 获取收款账号
public function getReceiptAccount()
{
$receipt_account = $this->getConfig(self::RECEIPT_ACCOUNT);
if (!$receipt_account) {
// 设置默认值
$receipt_account = '';
}
return $receipt_account;
}
} }
<?php
namespace App\Service\Common;
use App\Exceptions\UserException;
class CommonService
{
public const USER_CODE = 1; // 用户
// 自定义字段校验
public function customValidate($data, $fields, $messages = '校验未通过', $code_type = 1)
{
foreach ($fields as $field) {
if (blank($data[$field])) {
throw new UserException($code_type, $messages);
}
}
}
}
...@@ -2,7 +2,86 @@ ...@@ -2,7 +2,86 @@
namespace App\Service; namespace App\Service;
use App\Exceptions\UserException;
use App\Models\InscriptionTrading;
use App\Service\Common\CommonService;
class TradeService class TradeService
{ {
// 市场页面交易列表的筛选条件
// 铭文订单状态
public const ORDER_STATUS_WAIT = 1; // 未上架
public const ORDER_STATUS_ON = 2; // 已上架
public const ORDER_STATUS_SUCCESS = 3; // 已完成
public const ORDER_STATUS_FAIL = 4; // 已取消
// 卖家状态
public const SELLER_STATUS_WAIT = 1; // 未转移
public const SELLER_STATUS_PROGRESS = 2; // 进行中(hash已存在,正在检测铭文是否转移成功)
public const SELLER_STATUS_SUCCESS = 3; // 转移成功
public const SELLER_STATUS_FAIL = 4; // 转移失败
public const SELLER_STATUS_CANCEL = 5; // 取消转移(下架)
public const SELLER_STATUS_RECEIPT_FAIL = 6; // 卖家收款失败(平台支付失败)
public const SELLER_STATUS_RECEIPT_SUCCESS = 7; // 卖家收款成功
// 买家状态
public const BUYER_STATUS_WAIT = 1; // 未支付
public const BUYER_STATUS_PROGRESS = 2; // 进行中(hash已存在,正在检测是否支付成功)
public const BUYER_STATUS_SUCCESS = 3; // 支付成功
public const BUYER_STATUS_FAIL = 4; // 支付失败
public const BUYER_RECEIVE_FAIL = 5; // 买家接收铭文失败(平台转移失败)
public const BUYER_RECEIVE_SUCCESS = 6; // 买家接收铭文成功
public function model()
{
return new InscriptionTrading();
}
// 创建铭文交易
public function create($data)
{
return $this->model()->create($data);
}
public function userShelves($payment_address, $hash, $inscription, $price)
{
if (blank($payment_address) || blank($hash) || blank($inscription)) {
throw new UserException(1, '禁止访问');
}
// 铭文信息必须包含指定字段
$fields = ['content_uri', 'quantity', 'owner', 'creator', 'inscription_created_date', 'inscription_hash'];
// 校验铭文信息
app(CommonService::class)->customValidate($inscription, $fields, '缺少必要的铭文信息');
// 重复的hash禁止上架
$is_exist = $this->model()->where('hash', $hash)->first();
if ($is_exist) {
throw new UserException(1, '禁止访问');
}
// 卖家手续费比例
$sell_fee = app(AdminConfigService::class)->getSellFee();
// 手续费具体金额
$sell_fee_amount = $price * $sell_fee;
// 创建
$data = [
'content_uri' => $inscription['content_uri'],
'quantity' => $inscription['quantity'],
'owner' => $inscription['owner'],
'creator' => $inscription['creator'],
'inscription_created_date' => $inscription['inscription_created_date'],
'inscription_hash' => $inscription['inscription_hash'],
'original_amount' => $price,
// 收款账号
'admin_account' => app(AdminConfigService::class)->getReceiptAccount(),
'sell_fee' => $sell_fee,
'sell_fee_amount' => $sell_fee_amount,
'status' => self::ORDER_STATUS_WAIT,
'seller_status' => self::SELLER_STATUS_WAIT,
'buyer_status' => self::BUYER_STATUS_WAIT,
'seller_transfer_inscription_hash' => $hash,
];
$status = $this->create($data);
return true;
}
} }
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
// 铭文交易市场
Schema::create('inscription_trading', function (Blueprint $table) {
$table->id();
// 铭文数据
$table->text('content_uri')->comment('铭文数据(data:json)');
// 数量(amt)
$table->integer('quantity')->comment('总数量');
// 当前持有者
$table->string('owner')->comment('当前持有者');
// 创建者
$table->string('creator')->comment('创建者');
// 铭文创建时间
$table->dateTime('inscription_created_date')->comment('铭文创建时间');
// 铭文上的原始hash
$table->string('inscription_hash')->comment('铭文上的hash');
// 原始金额--卖家输入的
$table->integer('original_amount')->comment('原始金额');
// 后台收款账号
$table->string('admin_account')->comment('后台收款账号');
// 卖出手续费比例
$table->integer('sell_fee')->default(0)->comment('卖出手续费比例');
// 卖出收取的实际手续费
$table->integer('sell_fee_amount')->default(0)->comment('卖出收取的实际手续费');
// 买入手续费比例
$table->integer('buy_fee')->default(0)->comment('买入手续费比例');
// 买入收取的实际手续费
$table->integer('buy_fee_amount')->default(0)->comment('买入收取的实际手续费');
// 订单状态
$table->integer('status')->default(0)->comment('订单状态');
// 卖家状态
$table->integer('seller_status')->default(0)->comment('卖家状态');
// 买家状态
$table->integer('buyer_status')->default(0)->comment('买家状态');
// 卖家转移铭文hash
$table->string('seller_transfer_inscription_hash')->nullable()->comment('卖家转移铭文hash');
// 卖家收款hash
$table->string('seller_receive_hash')->nullable()->comment('卖家收款hash');
// 卖家取消hash(下架,平台将铭文转移给卖家)
$table->string('seller_cancel_hash')->nullable()->comment('卖家取消hash');
// 买家支付hash
$table->string('buyer_pay_hash')->nullable()->comment('买家支付hash');
// 买家接收铭文hash
$table->string('buyer_receive_inscription_hash')->nullable()->comment('买家接收铭文hash');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('inscription_trading');
}
};
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('transaction_log', function (Blueprint $table) {
$table->id();
// to
$table->string('to')->comment('收款人地址');
//from
$table->string('from')->comment('付款人地址');
// 交易hash
$table->string('hash')->comment('交易hash');
// 状态
$table->unsignedTinyInteger('status')->default(0)->comment('交易状态');
// 交易类型
$table->unsignedTinyInteger('type')->default(0)->comment('交易类型');
// 交易金额
$table->decimal('amount', 20, 8)->default(0)->comment('交易金额');
// 错误信息
$table->text('error_message')->nullable()->comment('错误信息');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('transaction_log');
}
};
<?php <?php
return [ return [
'labels' => [ 'labels' => [
'AdminConfig' => '配置管理', 'AdminConfig' => '基础设置',
'admin-config' => '配置管理', 'admin-config' => '基础设置',
], ],
'fields' => [ 'fields' => [
'key' => '类型', 'key' => '类型',
......
...@@ -35,21 +35,22 @@ ...@@ -35,21 +35,22 @@
<SellDialog <SellDialog
v-model="dialog_info.status" v-model="dialog_info.status"
:info="dialog_info.info" :info="dialog_info.info"
:fee="current_fee" :fee="app_info.sell_fee"
></SellDialog> ></SellDialog>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, onMounted, computed } from "vue"; import { ref, reactive, onMounted, computed, inject } from "vue";
import { isDev, getLocal } from "@/utils/tool"; import { isDev, getLocal } from "@/utils/tool";
import { userWalletKey } from "@/constants/token"; import { userWalletKey } from "@/constants/token";
import { test_wallet_list } from "@/constants/testData"; import { test_wallet_list, my_account_list } from "@/constants/testData";
import GroupButton from "@/components/groupButton.vue"; import GroupButton from "@/components/groupButton.vue";
import CustomCard from "@/components/card.vue"; import CustomCard from "@/components/card.vue";
import { useStore } from "vuex"; import { useStore } from "vuex";
import SellDialog from "./SellDialog.vue"; import SellDialog from "./SellDialog.vue";
import { inscriptionListFilter } from "@/utils/api/public"; import { inscriptionListFilter } from "@/utils/api/public";
import { inertia_data } from "@/constants/token";
const store = useStore(); const store = useStore();
const imgs = { const imgs = {
eth: new URL("../../../assets/svg/trade/eth2.svg", import.meta.url).href, eth: new URL("../../../assets/svg/trade/eth2.svg", import.meta.url).href,
...@@ -59,8 +60,9 @@ const dialog_info = reactive({ ...@@ -59,8 +60,9 @@ const dialog_info = reactive({
status: false, status: false,
info: {}, info: {},
}); });
// 手续费比例 // 全局数据
const current_fee = ref("1"); const app_info = inject(inertia_data);
// 当前选择的按钮 // 当前选择的按钮
const currentBtn = ref("1"); const currentBtn = ref("1");
// 按钮组 // 按钮组
...@@ -125,7 +127,7 @@ const getList = async () => { ...@@ -125,7 +127,7 @@ const getList = async () => {
if (isDev()) { if (isDev()) {
console.log(address); console.log(address);
// 本地环境 // 本地环境
listResult(test_wallet_list); listResult(my_account_list);
} else { } else {
tableList.loading = true; tableList.loading = true;
const res: any = await getUserInscriptionList(address); const res: any = await getUserInscriptionList(address);
......
...@@ -46,17 +46,25 @@ ...@@ -46,17 +46,25 @@
</template> </template>
<template #footer> <template #footer>
<div class="sell-dialog-footer"> <div class="sell-dialog-footer">
<t-button class="sell-cancel-button">取消</t-button> <t-button class="sell-cancel-button" @click="onCanel"
<t-button class="sell-confirm-button">确认</t-button> >取消</t-button
>
<t-button class="sell-confirm-button" @click="onSubmit"
>确认</t-button
>
</div> </div>
</template> </template>
</t-dialog> </t-dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { computed, ref, watch } from "vue"; import { computed, inject, ref, watch } from "vue";
import CustomCard from "@/components/card.vue"; import CustomCard from "@/components/card.vue";
import CustomInput from "@/components/input/index.vue"; import CustomInput from "@/components/input/index.vue";
import { showMessage } from "@/utils/tool";
import { inertia_data } from "@/constants/token";
import { inscriptionTransfer } from "@/utils/ethers";
import { useStore } from "vuex";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
...@@ -67,7 +75,11 @@ const props = withDefaults( ...@@ -67,7 +75,11 @@ const props = withDefaults(
{} {}
); );
const emit = defineEmits(["update:modelValue"]); const emit = defineEmits(["update:modelValue"]);
const store = useStore();
const userAddress = computed(() => store.getters["user/address"]);
const visible = ref(props.modelValue); const visible = ref(props.modelValue);
// 后台注入的内容
const app_info = inject(inertia_data);
// 输入的价格 // 输入的价格
const price = ref(""); const price = ref("");
...@@ -95,6 +107,44 @@ watch( ...@@ -95,6 +107,44 @@ watch(
emit("update:modelValue", v); emit("update:modelValue", v);
} }
); );
const onCanel = () => {
visible.value = false;
};
const onSubmit = () => {
const { info } = props;
if (!price.value) {
showMessage("请输入价格");
return;
}
// 最低价格
let sell_min_price = app_info.sell_min_price;
if (price.value < parseFloat(sell_min_price + "")) {
showMessage(`最低价格为${sell_min_price}U`);
return;
}
// 收款账号
let receipt_account = app_info.receipt_account;
if (!receipt_account) {
showMessage("account-empty", "error");
return;
}
// from 地址
let from = userAddress.value.address;
if (!from) {
showMessage("缺少from address");
return;
}
// data数据
let data = info.content_uri;
if (!data) {
showMessage("没有data数据");
return;
}
// 可以转移
inscriptionTransfer(receipt_account, from, data);
};
</script> </script>
<style lang="less"> <style lang="less">
......
...@@ -18,7 +18,7 @@ import { Head } from "@inertiajs/vue3"; ...@@ -18,7 +18,7 @@ import { Head } from "@inertiajs/vue3";
import Navbar from "@/components/navbar.vue"; import Navbar from "@/components/navbar.vue";
import CustomTable from "@/components/table.vue"; import CustomTable from "@/components/table.vue";
import CustomInput from "@/components/input/index.vue"; import CustomInput from "@/components/input/index.vue";
import { reactive, ref } from "vue"; import { reactive, ref, provide } from "vue";
import CustomGroupButton from "@/components/groupButton.vue"; import CustomGroupButton from "@/components/groupButton.vue";
import TipsSvg from "@/assets/svg/content/tips.svg"; import TipsSvg from "@/assets/svg/content/tips.svg";
import CustomTooltip from "@/components/tooltip.vue"; import CustomTooltip from "@/components/tooltip.vue";
...@@ -29,7 +29,10 @@ import { test_wallet_list } from "@/constants/testData"; ...@@ -29,7 +29,10 @@ import { test_wallet_list } from "@/constants/testData";
import CustomTabs from "@/components/tabs.vue"; import CustomTabs from "@/components/tabs.vue";
import MyInscription from "./components/MyInscription.vue"; import MyInscription from "./components/MyInscription.vue";
import TradeLog from "./components/TradeLog.vue"; import TradeLog from "./components/TradeLog.vue";
defineProps({ info: Object }); import { inertia_data } from "@/constants/token";
const props = defineProps({ info: Object });
provide(inertia_data, props.info);
// 请求接口放这里 // 请求接口放这里
...@@ -57,6 +60,7 @@ const tabList = [ ...@@ -57,6 +60,7 @@ const tabList = [
margin: 0 auto; margin: 0 auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.shelves-label { .shelves-label {
font-size: 31px; font-size: 31px;
font-weight: 600; font-weight: 600;
......
...@@ -2496,3 +2496,55 @@ export const test_wallet_list = [ ...@@ -2496,3 +2496,55 @@ export const test_wallet_list = [
min_block_confirmations: 63718, min_block_confirmations: 63718,
}, },
]; ];
// 测试账户上的铭文
export const my_account_list = [
{
transaction_hash:
"0x32360056d88b1bc44eaa6da76a8334c868ec8891ac00abe99f5116468a3bb377",
current_owner: "0x53d05d2f8bdbb5ce389d313cd6d320fb0fb1c397",
content_uri:
'data:,{"p":"erc-20","op":"mint","tick":"punk","id":"18662","amt":"1"}',
creator: "0x53d05d2f8bdbb5ce389d313cd6d320fb0fb1c397",
creation_timestamp: "2023-06-29T07:15:35.000Z",
valid_data_uri: true,
ethscription_number: "",
ethereum_punk_id: null,
finalization_status: "pending",
block_confirmations: 2,
min_block_confirmations: 2,
overall_order_number_as_int: 17583407000094000000,
},
{
transaction_hash:
"0xeb9007bd2a8bcad25f0df0f3b9ee1b6cff693d114d6ccf79a5dfb2af8079c706",
current_owner: "0x53d05d2f8bdbb5ce389d313cd6d320fb0fb1c397",
content_uri:
'data:,{"p":"erc-20","op":"mint","tick":"punk","id":"18622","amt":"1"}',
creator: "0x53d05d2f8bdbb5ce389d313cd6d320fb0fb1c397",
creation_timestamp: "2023-06-29T07:14:59.000Z",
valid_data_uri: true,
ethscription_number: "",
ethereum_punk_id: null,
finalization_status: "pending",
block_confirmations: 5,
min_block_confirmations: 5,
overall_order_number_as_int: 17583404000116000000,
},
{
transaction_hash:
"0x911d92a48d489ad367a50688e15af6a49274045c919305f0601b7c8f78098295",
current_owner: "0x53d05d2f8bdbb5ce389d313cd6d320fb0fb1c397",
content_uri:
'data:,{"p":"erc-20","op":"mint","tick":"punk","id":"18624","amt":"1"}',
creator: "0x53d05d2f8bdbb5ce389d313cd6d320fb0fb1c397",
creation_timestamp: "2023-06-29T07:14:11.000Z",
valid_data_uri: true,
ethscription_number: 350780,
ethereum_punk_id: null,
finalization_status: "partially_confirmed",
block_confirmations: 9,
min_block_confirmations: 9,
overall_order_number_as_int: 17583400000131000000,
},
];
...@@ -3,3 +3,6 @@ export const emailReg = /^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,8}){1,2}$/; ...@@ -3,3 +3,6 @@ export const emailReg = /^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,8}){1,2}$/;
// 用户钱包地址key // 用户钱包地址key
export const userWalletKey = "ConnectFox"; export const userWalletKey = "ConnectFox";
// inertia 注入到页面的数据key
export const inertia_data = "app_info";
...@@ -8,3 +8,5 @@ export const getUserInscriptionList = (address: string) => { ...@@ -8,3 +8,5 @@ export const getUserInscriptionList = (address: string) => {
}, },
}); });
}; };
// 卖家上架铭文
import { ethers } from "ethers"; import { ethers } from "ethers";
import { MessagePlugin } from "tdesign-vue-next"; import { MessagePlugin } from "tdesign-vue-next";
import ERC20ABI from "./ERC20ABI.json"; import ERC20ABI from "./ERC20ABI.json";
import { ConvertToHexadecimal } from "@/utils/tool";
let eth: any = window; let eth: any = window;
// 发起交易--小狐狸-tp支付 // 发起交易--小狐狸-tp支付
...@@ -38,8 +40,37 @@ export const fox_EtherPay = async (to: string, price: number) => { ...@@ -38,8 +40,37 @@ export const fox_EtherPay = async (to: string, price: number) => {
}; };
// 铭文转移 // 铭文转移
export const inscriptionTransfer = async (to: string) => { export const inscriptionTransfer = async (
// to: string,
from: string,
data: any
) => {
// data转16进制
let data16 = ConvertToHexadecimal(data);
console.log(data16);
try {
const res: any = await eth.ethereum.request({
method: "eth_sendTransaction",
params: [
{
from: from,
to: to,
value: 0,
data: data16,
// gasLimit: "0x5028",
// maxPriorityFeePerGas: "0x3b9aca00",
// maxFeePerGas: "0x2540be400",
},
],
});
// 获取交易hash
} catch (e: any) {
console.log(e);
if (e.code) {
MessagePlugin.warning(e.code);
}
return "";
}
}; };
export const bk_EtherPay = async (to: string, price: number) => { export const bk_EtherPay = async (to: string, price: number) => {
......
...@@ -143,3 +143,75 @@ export const getCreatedHowLongAgo = ( ...@@ -143,3 +143,75 @@ export const getCreatedHowLongAgo = (
return interval; return interval;
} }
}; };
// 字符串转换UTF8字节
export function strToUtf8Bytes(str: string) {
const utf8 = [];
for (let ii = 0; ii < str.length; ii++) {
let charCode = str.charCodeAt(ii);
if (charCode < 0x80) utf8.push(charCode);
else if (charCode < 0x800) {
utf8.push(0xc0 | (charCode >> 6), 0x80 | (charCode & 0x3f));
} else if (charCode < 0xd800 || charCode >= 0xe000) {
utf8.push(
0xe0 | (charCode >> 12),
0x80 | ((charCode >> 6) & 0x3f),
0x80 | (charCode & 0x3f)
);
} else {
ii++;
charCode =
0x10000 +
(((charCode & 0x3ff) << 10) | (str.charCodeAt(ii) & 0x3ff));
utf8.push(
0xf0 | (charCode >> 18),
0x80 | ((charCode >> 12) & 0x3f),
0x80 | ((charCode >> 6) & 0x3f),
0x80 | (charCode & 0x3f)
);
}
}
//兼容汉字,ASCII码表最大的值为127,大于127的值为特殊字符
for (let jj = 0; jj < utf8.length; jj++) {
let code: any = utf8[jj];
if (code > 127) {
utf8[jj] = code - 256;
}
}
return utf8;
}
// 根据返回字节码进行16进制转换
export function strToHexCharCode(str: any) {
var hexCharCode = [];
var chars = [
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"A",
"B",
"C",
"D",
"E",
"F",
];
for (var i = 0; i < str.length; i++) {
var bit = (str[i] & 0x0f0) >> 4;
hexCharCode.push(chars[bit]);
var bit = str[i] & 0x0f;
hexCharCode.push(chars[bit]);
}
return hexCharCode.join("");
}
// 字符串转16进制
export const ConvertToHexadecimal = (data: any) => {
return strToHexCharCode(strToUtf8Bytes(data));
};
...@@ -25,7 +25,9 @@ ...@@ -25,7 +25,9 @@
Route::group([ Route::group([
], function () { ], function () {
// 指定钱包的铭文列表 // 指定钱包的铭文列表
Route::get('/ethscriptions/owned_by','InscriptionController@wallet'); Route::get('/ethscriptions/owned_by', 'InscriptionController@wallet');
// 铭文上架
Route::post('/shelves', 'TradeController@shelves');
}); });
// // 需要登录 // // 需要登录
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment