跳到主要内容
ArcBlock Community

请教如何通过代理购买NFT

shenxiuqiang
支持
chain-and-bridgeopenqa

我想扣alic的钱,通过dapp为bob生成NFT,不知道该怎么写,对这些还不太了解,下面的写法返回错误:

javascript
const GraphQLClient = require('@ocap/client');
const getWallet = require('@blocklet/sdk/lib/wallet');
const env = require('./env');
const { aliceWallet, bobWallet } = require('./accont');

const logger = console;
const wallet = getWallet();
const client = new GraphQLClient(env.chainHost);
const endpoint = `${env.appUrl}/download/id`;
const factory = 'z3CtFVtpJ6AG4Bvd2eMf9sEiY5dvTR1gPdiRC';
const subject = 'mail subject';
const inputs = { endpoint, subject };

(async () => {
  const itx = await client.preMintAsset({
    factory,
    inputs,
    owner: bobWallet.address,
    wallet,
  });

  const tx = {
    from: wallet.address,
    pk: wallet.publicKey,
    delegator: wallet.address,
    itx: {
      factory: 'z3CtFVtpJ6AG4Bvd2eMf9sEiY5dvTR1gPdiRC',
      address: itx.address,
      assets: [],
      variables: Object.entries(itx.variables).map(([key, value]) => ({ name: key, value })),
      issuer: itx.issuer,
    },
  };
  const sign = await client.signAcquireAssetV2Tx({ tx, delegator: wallet.address, wallet: aliceWallet });
  logger.log(JSON.stringify(sign));
  // {"from":"zNKc7JoAXCbEDxa4WTYgNp6395HkWyY2Go9d","nonce":1722508058448,"chainId":"beta","pk":{"0":151,"1":80,"2":11,"3":26,"4":159,"5":101,"6":158,"7":13,"8":206,"9":169,"10":157,"11":120,"12":142,"13":229,"14":187,"15":97,"16":13,"17":203,"18":103,"19":158,"20":105,"21":97,"22":74,"23":32,"24":23,"25":146,"26":203,"27":226,"28":211,"29":29,"30":45,"31":68},"gas":0,"delegator":"zNKc7JoAXCbEDxa4WTYgNp6395HkWyY2Go9d","signature":"0xdbc530aefb9ef5b2b2e63b64c6ef287ab8cc3995f2bc8a54a54073149a8a6de6e7394c1cceb62bd13d12a8ac4379b866baf60ad9642ee524aa22af40b3f0cd07","signaturesList":[],"itx":{"typeUrl":"fg:t:acquire_asset_v2","value":"CiV6M0N0RlZ0cEo2QUc0QnZkMmVNZjlzRWlZNWR2VFIxZ1BkaVJDEiR6amR2aHhxRGFQUG9MQ29IS0FTR0s4UzlvcWVXNVVhNkR0NGsiAwoBMCIDCgExKmUKJHpOS2M3Sm9BWENiRUR4YTRXVFlnTnA2Mzk1SGtXeVkyR285ZBItekJCZk1VdmNxNTVFenFZakhMRmhzMThNWnducEFGQVBaM0xFUDN6Rmt1TFNYGg5kaWRtYWlsLXNlcnZlcg=="},"receiptsList":[],"serviceFee":"0"}
  
  const acquire = await client.sendAcquireAssetV2Tx({ tx: sign, delegator: wallet.address, wallet });
  logger.log(JSON.stringify(acquire));
})();
javascript
errors: [
      {
        code: 'INVALID_SIGNATURE',
        message: 'tx.signature is invalid',
        locations: [{ line: 2, column: 3 }],
        stack: [],
        path: ['sendTx'],
      },
    ],

6 条回复

wangshijun2年前

我想扣alic的钱,通过dapp为bob生成NFT

这个场景看起来有点“奇怪”,通常是 alice 授权给 dapp,然后 dapp 根据授权发送交易扣 alice 的钱,直接给 alice 生成 nft。

如果需要通过授权(delegation)来发送交易,需要按如下流程:

  1. 搞清楚 delegation 的 delegator(授权人)、delegatee(被授权人)
  2. delegator 签名交易并发送到链上,授权给 delegatee,就好比现实世界的委托合同,需要双方签字,并且合同载明委托事项、有效期等
  3. delegatee 根据授权内容在授权范围内发送交易,交易中需要携带 delegator,你上面已经这么做了

你上面缺失的部分是第2步,示例如下:

javascriptCopy
const alice = fromSerectKey(aliceSecretKey);
const dapp = fromAddress(dappAddress);

const [hash, address] = await client.delegate({
  from: alice,
  to: dapp,
  privileges: [
    {
      typeUrl: 'fg:t:acquire_asset_v2',
    },
  ],
});

因为现实的业务场景中,alice 的私钥通常是保管在 DID Wallet 中,需要 alice 签名授权交易则需要通过 DID Connect,拿到签名交易之后发送出去。

shenxiuqiang2年前

使用场景是alice发送加密邮件给bob,但邮件是先发送到dapp server端,由dapp保存邮件,生成NFT个收件人bob,NFT里面保存了dapp加密后的邮件下载地址。这个生成NFT的时候由Alice对交易进行签名授权扣除alice的钱,

我在playground里看到的示例:

image.png

我看到client里的signAcquireAssetV2Tx 就觉得是用来做签名授权的,

流程上,alice提交到server保存数据,server生成交易tx,通过响应返给alice,alice通过signAcquireAssetV2Tx签名后再提交给server,server提交sendAcquireAssetV2Tx交易,扣除alice的资产,不知是否可以这样理解。

shenxiuqiang2年前

tx 里的from、pk 是写 alice还是dapp server的, delegator, 是dapp server 的还是 client.delegate 返回的address

signAcquireAssetV2Tx 的wallet 应该是alice的,sendAcquireAssetV2Tx 的wallet 应该是dapp server的吧。

wangshijun2年前

如果仅仅是邮件的加密,不涉及 NFT 或者 Token 会更简单?发送邮件的人支付费用是把双刃剑,一方面能 anti-spam,另外一方面可能会降低使用率。

shenxiuqiang2年前(edited)

发了代理delegate请求还是不行:

alice地址:https://explorer.abtnetwork.io/explorer/accounts/z1oD9tDAcYxfS1GF8iAhZSTaPYUpfkbrefo

delegate 地址

image.png

不知程序哪里错了

javascriptCopy
const GraphQLClient = require('@ocap/client');
const getWallet = require('@blocklet/sdk/lib/wallet');
const env = require('./env');
const { aliceWallet, bobWallet } = require('./accont');

const logger = console;
const wallet = getWallet();
const client = new GraphQLClient(env.chainHost);
const endpoint = `${env.appUrl}/download/id`;
const factory = 'z3CtFVtpJ6AG4Bvd2eMf9sEiY5dvTR1gPdiRC';
const subject = 'mail subject';
const inputs = { endpoint, subject };

(async () => {
  // const [hash] = await client.delegate({
  //   from: aliceWallet,
  //   to: wallet,
  //   privileges: [
  //     {
  //       typeUrl: 'fg:t:acquire_asset_v2',
  //     },
  //   ],
  // });
  // logger.log('hash', hash);
  const delegator = aliceWallet.address;
  // const delegator = 'z2bNA6XY7Xv8MXkfQH773tyPiagPR2F3M63o4';
  const itx = await client.preMintAsset({
    factory,
    inputs,
    owner: bobWallet.address,
    wallet,
  });

  // logger.log(itx);
  const tx = await client.signAcquireAssetV2Tx({
    tx: {
      from: aliceWallet.address,
      pk: aliceWallet.publicKey,
      delegator,
      itx: {
        factory: 'z3CtFVtpJ6AG4Bvd2eMf9sEiY5dvTR1gPdiRC',
        address: itx.address,
        assets: [],
        variables: itx.variables,
        issuer: itx.issuer,
      },
    },
    delegator,
    wallet: aliceWallet,
  });
  logger.log(JSON.stringify(tx));
  const acquire = await client.sendAcquireAssetV2Tx({ tx, delegator, wallet });
  logger.log(JSON.stringify(acquire));
})();

Error: /Users/shenxiuqiang/workspace/didmail/server/node_modules/.pnpm/@arcblock+sdk-util@0.34.3/node_modules/@arcblock/sdk-util/lib/index.js:275
        const err = new Error("GraphQLError: ".concat(json.errors.map(x => x.message).join('; ')));
                    ^

Error: GraphQLError: No delegation found between sender and delegator
    at NativeGraphqlClient._doRequest (/Users/shenxiuqiang/workspace/didmail/server/node_modules/.pnpm/@arcblock+sdk-util@0.34.3/node_modules/@arcblock/sdk-util/lib/index.js:275:21)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async /Users/shenxiuqiang/workspace/didmail/server/node_modules/.pnpm/@ocap+client@1.18.126/node_modules/@ocap/client/lib/extension.js:398:28 {
  errors: [
    {
      code: 'INVALID_DELEGATION',
      message: 'No delegation found between sender and delegator',
      locations: [ { line: 2, column: 3 } ],
      stack: [],
      path: [ 'sendTx' ]
    }
  ],
  txHash: 'FB6FC50B867B566A9E067E51E4307AC4CD5EB06402B21A2A5C5C3E8A5C0F84A3'
}
shenxiuqiang2年前

使用delegate后可以扣除 alice 的资产,但是 asset属于server,而不是设置的owner bob,这个owner并不是我理解的那样会转给bob:

https://explorer.abtnetwork.io/explorer/txs/215CA945C1090FE00251945C213B67D9002E8E4431F286DD5BC717D804967A01

image.png

javascriptCopy
/* eslint-disable @typescript-eslint/no-unused-vars */
const GraphQLClient = require('@ocap/client');
const getWallet = require('@blocklet/sdk/lib/wallet');
const env = require('./env');
const { aliceWallet, bobWallet } = require('./accont');

const logger = console;
const wallet = getWallet();
const client = new GraphQLClient(env.chainHost);
const endpoint = `${env.appUrl}/download/id`;
const factory = 'z3CtFVtpJ6AG4Bvd2eMf9sEiY5dvTR1gPdiRC';
const subject = 'mail subject';
const inputs = { endpoint, subject };

(async () => {
  const [hash] = await client.delegate({
    from: aliceWallet,
    to: wallet,
    privileges: [
      {
        typeUrl: 'fg:t:acquire_asset_v2',
      },
    ],
  });
  const itx = await client.preMintAsset({
    factory,
    inputs,
    owner: bobWallet.address,
    wallet,
  });
  client.acquireAsset({
    itx,
    delegator: aliceWallet.address,
    wallet,
  });
})();
回复